diff --git a/README.md b/README.md index 6db9fcb..79fb745 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,215 @@ -# LeetCode-in-Python -LeeteCode-in-Python is a GitHub repo with Python solutions to LeetCode problems. It offers clean, efficient, and well-documented code for interview prep, competitive programming, and mastering algorithms. Solutions are categorized by difficulty and include explanations for clarity. Regularly updated, it emphasizes Pythonic practices. +# LeetCode Python Solutions + +![LeetCode Logo](https://upload.wikimedia.org/wikipedia/commons/1/19/LeetCode_logo_black.png) + +This repository contains Python solutions for various LeetCode problems. Each problem is organized in its own directory under the `Solution/` folder, with a `readme.md` file providing the problem description, examples, constraints, and solutions in multiple programming languages. + +## 🌟 Why Use This Repository? + +#### **"Success is the sum of small efforts, repeated day in and day out."** β€” Robert Collier + +This repository is designed to help you: + +- **Master Problem-Solving**: Tackle a wide range of LeetCode problems with clear and concise solutions. +- **Learn Efficiently**: Understand optimized approaches and advanced techniques. +- **Stay Motivated**: Progress step by step, and see your skills grow with every solved problem. +- **Collaborate and Contribute**: Join a community of learners and developers to share knowledge and improve together. + +Whether you're preparing for coding interviews, enhancing your algorithmic skills, or just exploring the joy of problem-solving, this repository is your companion on the journey to success. + +--- + +## πŸ“‘ Table of Contents + +- [πŸš€ Features](#-features) +- [πŸ“‚ Repository Structure](#-repository-structure) +- [πŸ› οΈ How to Use](#️-how-to-use) +- [🌟 Highlights](#-highlights) +- [🀝 Contributing](#-contributing) + - [Steps to Contribute](#steps-to-contribute) + - [Contribution Graph](#contribution-graph) +- [πŸ“œ License](#-license) +- [πŸ“Š Statistics](#-statistics) +- [πŸ“Œ Quick Links](#-quick-links) +- [Index of LeetCode Python Solutions](#index-of-leetcode-python-solutions) + +## πŸš€ Features + +- **Comprehensive Solutions**: Includes Python solutions for a wide range of LeetCode problems. +- **Multi-Language Support**: Problem descriptions and solutions are available in multiple programming languages. +- **Organized Structure**: Each problem is neatly organized in its own directory with a dedicated `readme.md` file. +- **Interactive and Informative**: Easy-to-navigate structure with detailed explanations and examples. + +## πŸ“‚ Repository Structure + +```mermaid +graph TD + A[Root Directory] --> B[LICENSE] + A --> C[README.md] + A --> D[.gitattribute] + A --> E[Solution/] + A --> E12[gitignore] + A --> E14[workflow] + E --> F[LeetCode Qutions] + F --> |follow instructions| F1[README.md] + G[Readme.md] + F --> |Edit For Contribute| G1[Solutions.py] +``` + +## πŸ› οΈ How to Use + +1. Navigate to the `Solution/` folder. +2. Find the directory corresponding to the problem you are interested in (e.g., `104. Maximum Depth of Binary Tree`). +3. Open the `readme.md` file for the problem description, examples, and solutions. +4. Review the Python solution in the `.py` file. + +## 🌟 Highlights + +- **Beginner-Friendly**: Solutions are written in a clear and concise manner, making them easy to understand. +- **Advanced Techniques**: Includes optimized solutions for complex problems. +- **Regular Updates**: The repository is continuously updated with new problems and solutions. + +## 🀝 Contributing + +Contributions are welcome! If you have a better solution or additional test cases, feel free to submit a pull request. + +### Steps to Contribute + +1. Fork the repository. +2. Create a new branch for your changes. +3. Add your solution or update an existing one. +4. Commit your changes with a descriptive message. +5. Submit a pull request. + +### Contribution Graph + +```mermaid +graph TD + A[Contributors] --> B[Add New Solutions] + A --> C[Fix Bugs in Existing Solutions] + A --> D[Improve Documentation] + A --> E[Add Test Cases] + B --> F[Python Solutions] + B --> G[Multi-Language Support] + C --> H[Code Optimization] + D --> I[Update README.md] + D --> J[Add Problem Descriptions] + E --> K[Edge Cases] + E --> L[Performance Tests] +``` + +### Contribution Graph + +```mermaid +graph TB; + A[Contributors] --> B[Fork] + B --> C[Clone in your system] + C --> D[Create Branch] + D --> E[Add Solution or Update Existing One] + E --> F[Commit Changes] + F --> G[Push Changes] + E --> L[Add Performance] + L --> M[Add Test Cases] + M --> N[Add Edge Cases] + N --> O[ Performance Tests] -->H + G --> H[Create Pull Request] + H --> I[Merge Pull Request] + I --> J[Add Reviewer of owner] + J --> K[Add lebels] + +``` + +## πŸ“œ License + +This repository is licensed under the MIT License. See the `LICENSE` file for more details. + +--- + +## πŸ“Š Statistics + +- **Total Problems Solved**: 100+ (and counting!) +- **Languages Supported**: Python, Java, C++, Go, TypeScript +- **Difficulty Levels**: Easy, Medium, Hard + +--- + +## πŸ“Œ Quick Links + +- [LeetCode Website](https://leetcode.com/) +- [Contribute to this Repo](https://github.com/your-repo-link) +- [MIT License](LICENSE) + +--- + +![Happy Coding](https://media.giphy.com/media/3o7abldj0b3rxrZUxW/giphy.gif) + +## Index of LeetCode Python Solutions + +This index provides a quick overview of all the problems and solutions available in this repository. Each problem is organized under the `Solution/` folder, and older solutions are stored in the `privious/` folder. + +## πŸ“‚ Solution Directory + +### Problems by ID + +- [**1004. Max Consecutive Ones III**](Solution/1004.%20Max%20Consecutive%20Ones%20III/readme.md) +- [**104. Maximum Depth of Binary Tree**](Solution/104.%20Maximum%20Depth%20of%20Binary%20Tree/readme.md) +- [**11. Container With Most Water**](Solution/11.%20Container%20With%20Most%20Water/readme.md) +- [**1161. Maximum Level Sum of a Binary Tree**](Solution/1161.%20Maximum%20Level%20Sum%20of%20a%20Binary%20Tree/readme.md) +- [**1207. Unique Number of Occurrences**](Solution/1207.%20Unique%20Number%20of%20Occurrences/readme.md) +- [**1372. Longest ZigZag Path in a Binary Tree**](Solution/1372.%20Longest%20ZigZag%20Path%20in%20a%20Binary%20Tree/readme.md) +- [**1448. Count Good Nodes in Binary Tree**](Solution/1448.%20Count%20Good%20Nodes%20in%20Binary%20Tree/readme.md) +- [**1456. Maximum Number of Vowels in a Substring of Given Length**](Solution/1456.%20Maximum%20Number%20of%20Vowels%20in%20a%20Substring%20of%20Given%20Length/readme.md) +- [**1466. Reorder Routes to Make All Paths Lead to the City Zero**](Solution/1466.%20Reorder%20Routes%20to%20Make%20All%20Paths%20Lead%20to%20the%20City%20Zero/readme.md) +- [**1493. Longest Subarray of 1's After Deleting One Element**](Solution/1493.%20Longest%20Subarray%20of%201's%20After%20Deleting%20One%20Element/readme.md) +- [**151. Reverse Words in a String**](Solution/151.%20Reverse%20Words%20in%20a%20String/readme.md) +- [**1657. Determine if Two Strings Are Close**](Solution/1657.%20Determine%20if%20Two%20Strings%20Are%20Close/readme.md) +- [**1679. Max Number of K-Sum Pairs**](Solution/1679.%20Max%20Number%20of%20K-Sum%20Pairs/readme.md) +- [**1732. Find the Highest Altitude**](Solution/1732.%20Find%20the%20Highest%20Altitude/readme.md) +- [**1926. Nearest Exit from Entrance in Maze**](Solution/1926.%20Nearest%20Exit%20from%20Entrance%20in%20Maze/readme.md) +- [**199. Binary Tree Right Side View**](Solution/199.%20Binary%20Tree%20Right%20Side%20View/readme.md) +- [**206. Reverse Linked List**](Solution/206.%20Reverse%20Linked%20List/readme.md) +- [**2095. Delete the Middle Node of a Linked List**](Solution/2095.%20Delete%20the%20Middle%20Node%20of%20a%20Linked%20List/readme.md) +- [**2130. Maximum Twin Sum of a Linked List**](Solution/2130.%20Maximum%20Twin%20Sum%20of%20a%20Linked%20List/readme.md) +- [**215. Kth Largest Element in an Array**](Solution/215.%20Kth%20Largest%20Element%20in%20an%20Array/readme.md) +- [**2215. Find the Difference of Two Arrays**](Solution/2215.%20Find%20the%20Difference%20of%20Two%20Arrays/readme.md) +- [**2336. Smallest Number in Infinite Set**](Solution/2336.%20Smallest%20Number%20in%20Infinite%20Set/readme.md) +- [**2352. Equal Row and Column Pairs**](Solution/2352.%20Equal%20Row%20and%20Column%20Pairs/readme.md) +- [**236. Lowest Common Ancestor of a Binary Tree**](Solution/236.%20Lowest%20Common%20Ancestor%20of%20a%20Binary%20Tree/readme.md) +- [**238. Product of Array Except Self**](Solution/238.%20Product%20of%20Array%20Except%20Self/readme.md) +- [**2390. Removing Stars From a String**](Solution/2390.%20Removing%20Stars%20From%20a%20String/readme.md) +- [**2462. Total Cost to Hire K Workers**](Solution/2462.%20Total%20Cost%20to%20Hire%20K%20Workers/readme.md) +- [**2542. Maximum Subsequence Score**](Solution/2542.%20Maximum%20Subsequence%20Score/readme.md) +- [**283. Move Zeroes**](Solution/283.%20Move%20Zeroes/readme.md) +- [**328. Odd Even Linked List**](Solution/328.%20Odd%20Even%20Linked%20List/readme.md) +- [**334. Increasing Triplet Subsequence**](Solution/334.%20Increasing%20Triplet%20Subsequence/readme.md) +- [**345. Reverse Vowels of a String**](Solution/345.%20Reverse%20Vowels%20of%20a%20String/readme.md) +- [**374. Guess Number Higher or Lower**](Solution/374.%20Guess%20Number%20Higher%20or%20Lower/readme.md) +- [**392. Is Subsequence**](Solution/392.%20Is%20Subsequence/readme.md) +- [**394. Decode String**](Solution/394.%20Decode%20String/readme.md) +- [**399. Evaluate Division**](Solution/399.%20Evaluate%20Division/readme.md) +- [**437. Path Sum III**](Solution/437.%20Path%20Sum%20III/readme.md) +- [**443. String Compression**](Solution/443.%20String%20Compression/readme.md) +- [**450. Delete Node in a BST**](Solution/450.%20Delete%20Node%20in%20a%20BST/readme.md) +- [**547. Number of Provinces**](Solution/547.%20Number%20of%20Provinces/readme.md) +- [**643. Maximum Average Subarray I**](Solution/643.%20Maximum%20Average%20Subarray%20I/readme.md) +- [**649. Dota2 Senate**](Solution/649.%20Dota2%20Senate/readme.md) +- [**700. Search in a Binary Search Tree**](Solution/700.%20Search%20in%20a%20Binary%20Search%20Tree/readme.md) +- [**724. Find Pivot Index**](Solution/724.%20Find%20Pivot%20Index/readme.md) +- [**735. Asteroid Collision**](Solution/735.%20Asteroid%20Collision/readme.md) +- [**841. Keys and Rooms**](Solution/841.%20Keys%20and%20Rooms/readme.md) + +## πŸ“‚ Previous Solutions Directory + +### Problems by ID + +- [**2115. Find All Possible Recipes from Given Supplies**](privious/2115.%20Find%20All%20Possible%20Recipes%20from%20Given%20Supplies.py) +- [**2206. Divide Array Into Equal Pairs**](privious/2206.%20Divide%20Array%20Into%20Equal%20Pairs.py) +- [**2226. Maximum Candies Allocated to K Children**](privious/2226.%20Maximum%20Candies%20Allocated%20to%20K%20Children.py) +- [**2560. House Robber IV**](privious/2560.%20House%20Robber%20IV.py) +- [**2594. Minimum Time to Repair Cars**](privious/2594.%20Minimum%20Time%20to%20Repair%20Cars.py) +- [**3356. Zero Array Transformation II**](privious/3356.%20Zero%20Array%20Transformation%20II.py) + +--- + +For detailed problem descriptions and solutions, navigate to the respective directories. + diff --git a/Solution/1466. Reorder Routes to Make All Paths Lead to the City Zero/1466. Reorder Routes to Make All Paths Lead to the City Zero.py b/Solution/1466. Reorder Routes to Make All Paths Lead to the City Zero/1466. Reorder Routes to Make All Paths Lead to the City Zero.py new file mode 100644 index 0000000..a8f58ae --- /dev/null +++ b/Solution/1466. Reorder Routes to Make All Paths Lead to the City Zero/1466. Reorder Routes to Make All Paths Lead to the City Zero.py @@ -0,0 +1,10 @@ +class Solution: + def minReorder(self, n: int, connections: List[List[int]]) -> int: + def dfs(a: int, fa: int) -> int: + return sum(c + dfs(b, a) for b, c in g[a] if b != fa) + + g = [[] for _ in range(n)] + for a, b in connections: + g[a].append((b, 1)) + g[b].append((a, 0)) + return dfs(0, -1) \ No newline at end of file diff --git a/Solution/1466. Reorder Routes to Make All Paths Lead to the City Zero/readme.md b/Solution/1466. Reorder Routes to Make All Paths Lead to the City Zero/readme.md new file mode 100644 index 0000000..bcc9cd3 --- /dev/null +++ b/Solution/1466. Reorder Routes to Make All Paths Lead to the City Zero/readme.md @@ -0,0 +1,331 @@ + + + +# [1466. Reorder Routes to Make All Paths Lead to the City Zero](https://leetcode.com/problems/reorder-routes-to-make-all-paths-lead-to-the-city-zero) + +--- +- **comments**: true +- **difficulty**: Medium +- **edit_url**: https://github.com/doocs/leetcode/edit/main/solution/1400-1499/1466.Reorder%20Routes%20to%20Make%20All%20Paths%20Lead%20to%20the%20City%20Zero/README_EN.md +- **rating**: 1633 +- **source**: Weekly Contest 191 Q3 +- **tags**: + - Depth-First Search + - Breadth-First Search + - Graph + +## Description + + + +

There are n cities numbered from 0 to n - 1 and n - 1 roads such that there is only one way to travel between two different cities (this network form a tree). Last year, The ministry of transport decided to orient the roads in one direction because they are too narrow.

+ +

Roads are represented by connections where connections[i] = [ai, bi] represents a road from city ai to city bi.

+ +

This year, there will be a big event in the capital (city 0), and many people want to travel to this city.

+ +

Your task consists of reorienting some roads such that each city can visit the city 0. Return the minimum number of edges changed.

+ +

It's guaranteed that each city can reach city 0 after reorder.

+ +

 

+

Example 1:

+ +
+Input: n = 6, connections = [[0,1],[1,3],[2,3],[4,0],[4,5]]
+Output: 3
+Explanation: Change the direction of edges show in red such that each node can reach the node 0 (capital).
+
+ +

Example 2:

+ +
+Input: n = 5, connections = [[1,0],[1,2],[3,2],[3,4]]
+Output: 2
+Explanation: Change the direction of edges show in red such that each node can reach the node 0 (capital).
+
+ +

Example 3:

+ +
+Input: n = 3, connections = [[1,0],[2,0]]
+Output: 0
+
+ +

 

+

Constraints:

+ + + + + +## Solutions + + + +### Solution 1: DFS + +The route map given in the problem has $n$ nodes and $n-1$ edges. If we ignore the direction of the edges, then these $n$ nodes form a tree. The problem requires us to change the direction of some edges so that each node can reach node $0$. + +We might as well consider starting from node $0$ and reaching all other nodes. The direction is opposite to the problem description, which means that when we build the graph, for the directed edge $[a, b]$, we should regard it as the directed edge $[b, a]$. That is to say, if it is from $a$ to $b$, we need to change the direction once; if it is from $b$ to $a$, no direction change is needed. + +Next, we only need to start from node $0$, search all other nodes, and during the process, if we encounter an edge that needs to change direction, we accumulate the number of direction changes once. + +The time complexity is $O(n)$, and the space complexity is $O(n)$. Here, $n$ is the number of nodes in the problem. + + + +#### Python3 + +```python +class Solution: + def minReorder(self, n: int, connections: List[List[int]]) -> int: + def dfs(a: int, fa: int) -> int: + return sum(c + dfs(b, a) for b, c in g[a] if b != fa) + + g = [[] for _ in range(n)] + for a, b in connections: + g[a].append((b, 1)) + g[b].append((a, 0)) + return dfs(0, -1) +``` + +#### Java + +```java +class Solution { + private List[] g; + + public int minReorder(int n, int[][] connections) { + g = new List[n]; + Arrays.setAll(g, k -> new ArrayList<>()); + for (var e : connections) { + int a = e[0], b = e[1]; + g[a].add(new int[] {b, 1}); + g[b].add(new int[] {a, 0}); + } + return dfs(0, -1); + } + + private int dfs(int a, int fa) { + int ans = 0; + for (var e : g[a]) { + int b = e[0], c = e[1]; + if (b != fa) { + ans += c + dfs(b, a); + } + } + return ans; + } +} +``` + +#### C++ + +```cpp +class Solution { +public: + int minReorder(int n, vector>& connections) { + vector> g[n]; + for (auto& e : connections) { + int a = e[0], b = e[1]; + g[a].emplace_back(b, 1); + g[b].emplace_back(a, 0); + } + function dfs = [&](int a, int fa) { + int ans = 0; + for (auto& [b, c] : g[a]) { + if (b != fa) { + ans += c + dfs(b, a); + } + } + return ans; + }; + return dfs(0, -1); + } +}; +``` + +#### Go + +```go +func minReorder(n int, connections [][]int) int { + g := make([][][2]int, n) + for _, e := range connections { + a, b := e[0], e[1] + g[a] = append(g[a], [2]int{b, 1}) + g[b] = append(g[b], [2]int{a, 0}) + } + var dfs func(int, int) int + dfs = func(a, fa int) (ans int) { + for _, e := range g[a] { + if b, c := e[0], e[1]; b != fa { + ans += c + dfs(b, a) + } + } + return + } + return dfs(0, -1) +} +``` + +#### TypeScript + +```ts +function minReorder(n: number, connections: number[][]): number { + const g: [number, number][][] = Array.from({ length: n }, () => []); + for (const [a, b] of connections) { + g[a].push([b, 1]); + g[b].push([a, 0]); + } + const dfs = (a: number, fa: number): number => { + let ans = 0; + for (const [b, c] of g[a]) { + if (b !== fa) { + ans += c + dfs(b, a); + } + } + return ans; + }; + return dfs(0, -1); +} +``` + +#### Rust + +```rust +impl Solution { + pub fn min_reorder(n: i32, connections: Vec>) -> i32 { + let mut g: Vec> = vec![vec![]; n as usize]; + for e in connections.iter() { + let a = e[0] as usize; + let b = e[1] as usize; + g[a].push((b as i32, 1)); + g[b].push((a as i32, 0)); + } + fn dfs(a: usize, fa: i32, g: &Vec>) -> i32 { + let mut ans = 0; + for &(b, c) in g[a].iter() { + if b != fa { + ans += c + dfs(b as usize, a as i32, g); + } + } + ans + } + dfs(0, -1, &g) + } +} +``` + + + + + + + +### Solution 2: BFS + +We can use the Breadth-First Search (BFS) method, starting from node $0$, to search all other nodes. During the process, if we encounter an edge that requires a change of direction, we increment the count of direction changes. + +The time complexity is $O(n)$, and the space complexity is $O(n)$. Where $n$ is the number of nodes in the problem. + + + +#### Python3 + +```python +class Solution: + def minReorder(self, n: int, connections: List[List[int]]) -> int: + g = [[] for _ in range(n)] + for a, b in connections: + g[a].append((b, 1)) + g[b].append((a, 0)) + q = deque([0]) + vis = {0} + ans = 0 + while q: + a = q.popleft() + for b, c in g[a]: + if b not in vis: + vis.add(b) + q.append(b) + ans += c + return ans +``` + +```java +class Solution { + public int minReorder(int n, int[][] connections) { + List[] g = new List[n]; + Arrays.setAll(g, k -> new ArrayList<>()); + for (var e : connections) { + int a = e[0], b = e[1]; + g[a].add(new int[] {b, 1}); + g[b].add(new int[] {a, 0}); + } + Deque q = new ArrayDeque<>(); + q.offer(0); + boolean[] vis = new boolean[n]; + vis[ + +0] = true; + int ans = 0; + while (!q.isEmpty()) { + int a = q.poll(); + for (var e : g[a]) { + int b = e[0], c = e[1]; + if (!vis[b]) { + vis[b] = true; + q.offer(b); + ans += c; + } + } + } + return ans; + } +} +``` + +```cpp +class Solution { +public: + int minReorder(int n, vector>& connections) { + vector> g[n]; + for (auto& e : connections) { + int a = e[0], b = e[1]; + g[a].emplace_back(b, 1); + g[b].emplace_back(a, 0); + } + queue q; + q.push(0); + vector vis(n, false); + vis[0] = true; + int ans = 0; + while (!q.empty()) { + int a = q.front(); + q.pop(); + for (auto& [b, c] : g[a]) { + if (!vis[b]) { + vis[b] = true; + q.push(b); + ans += c; + } + } + } + return ans; + } +}; +``` + + + + + + +``` diff --git a/Solution/1926. Nearest Exit from Entrance in Maze/1926. Nearest Exit from Entrance in Maze.py b/Solution/1926. Nearest Exit from Entrance in Maze/1926. Nearest Exit from Entrance in Maze.py new file mode 100644 index 0000000..5ed736d --- /dev/null +++ b/Solution/1926. Nearest Exit from Entrance in Maze/1926. Nearest Exit from Entrance in Maze.py @@ -0,0 +1,19 @@ +class Solution: + def nearestExit(self, maze: List[List[str]], entrance: List[int]) -> int: + m, n = len(maze), len(maze[0]) + i, j = entrance + q = deque([(i, j)]) + maze[i][j] = "+" + ans = 0 + while q: + ans += 1 + for _ in range(len(q)): + i, j = q.popleft() + for a, b in [[0, -1], [0, 1], [-1, 0], [1, 0]]: + x, y = i + a, j + b + if 0 <= x < m and 0 <= y < n and maze[x][y] == ".": + if x == 0 or x == m - 1 or y == 0 or y == n - 1: + return ans + q.append((x, y)) + maze[x][y] = "+" + return -1 \ No newline at end of file diff --git a/Solution/1926. Nearest Exit from Entrance in Maze/readme.md b/Solution/1926. Nearest Exit from Entrance in Maze/readme.md new file mode 100644 index 0000000..08d582e --- /dev/null +++ b/Solution/1926. Nearest Exit from Entrance in Maze/readme.md @@ -0,0 +1,258 @@ + + + + +# [1926. Nearest Exit from Entrance in Maze](https://leetcode.com/problems/nearest-exit-from-entrance-in-maze) +--- +- **comments**: true +- **difficulty**: Medium + +- **rating**: 1638 +- **source**: Biweekly Contest 56 Q2 +- **tags**: + - Breadth-First Search + - Array + - Matrix +--- +## Description + + + +

You are given an m x n matrix maze (0-indexed) with empty cells (represented as '.') and walls (represented as '+'). You are also given the entrance of the maze, where entrance = [entrancerow, entrancecol] denotes the row and column of the cell you are initially standing at.

+ +

In one step, you can move one cell up, down, left, or right. You cannot step into a cell with a wall, and you cannot step outside the maze. Your goal is to find the nearest exit from the entrance. An exit is defined as an empty cell that is at the border of the maze. The entrance does not count as an exit.

+ +

Return the number of steps in the shortest path from the entrance to the nearest exit, or -1 if no such path exists.

+ +

 

+

Example 1:

+ +
+Input: maze = [["+","+",".","+"],[".","",".",".","+"],["+","+","+","."]], entrance = [1,2]
+Output: 1
+Explanation:
+There are 3 exits in this maze at [1,0], [0,2], and [2,3].
+Initially, you are at the entrance cell [1,2].
+- You can reach [1,0] by moving 2 steps left.
+- You can reach [0,2] by moving 1 step up.
+It is impossible to reach [2,3] from the entrance.
+Thus, the nearest exit is [0,2], which is 1 step away.
+
+ +

Example 2:

+ +
+Input: maze = [["+","+","+"],[".","",".","."],["+","+","+"]], entrance = [1,0]
+Output: 2
+Explanation:
+There is 1 exit in this maze at [1,2].
+[1,0] does not count as an exit since it is the entrance cell.
+Initially, you are at the entrance cell [1,0].
+- You can reach [1,2] by moving 2 steps right.
+Thus, the nearest exit is [1,2], which is 2 steps away.
+
+ +

Example 3:

+ +
+Input: maze = [[".","+"]], entrance = [0,0]
+Output: -1
+Explanation:
+There are no exits in this maze.
+
+ +

 

+

Constraints:

+ +
    +
  • maze.length == m
  • +
  • maze[i].length == n
  • +
  • 1 <= m, n <= 100
  • +
  • maze[i][j] is either '. or '+'.
  • +
  • entrance.length == 2
  • +
  • 0 <= entrancerow < m
  • +
  • 0 <= entrancecol < n
  • +
  • entrance will always be an empty cell.
  • +
+ + + +## Solutions + + + +### Solution 1: BFS + +We can start from the entrance and perform a breadth-first search (BFS). Each time we reach a new empty cell, we mark it as visited and add it to the queue until we find an empty cell on the boundary, then return the number of steps. + +Specifically, we define a queue `q`, initially adding `entrance` to the queue. We define a variable `ans` to record the number of steps, initially set to `1`. Then we start the BFS. In each round, we take out all elements from the queue and traverse them. For each element, we try to move in four directions. If the new position is an empty cell, we add it to the queue and mark it as visited. If the new position is an empty cell on the boundary, we return `ans`. If the queue is empty, we return `-1`. After this round of search, we increment `ans` by one and continue to the next round of search. + +If we finish the traversal without finding an empty cell on the boundary, we return `-1`. + +The time complexity is `O(m Γ— n)`, and the space complexity is `O(m Γ— n)`. Here, `m` and `n` are the number of rows and columns in the maze, respectively. + + + +#### Python3 + +```python +from collections import deque +class Solution: + def nearestExit(self, maze: List[List[str]], entrance: List[int]) -> int: + m, n = len(maze), len(maze[0]) + i, j = entrance + q = deque([(i, j)]) + maze[i][j] = "+" + ans = 0 + while q: + ans += 1 + for _ in range(len(q)): + i, j = q.popleft() + for a, b in [[0, -1], [0, 1], [-1, 0], [1, 0]]: + x, y = i + a, j + b + if 0 <= x < m and 0 <= y < n and maze[x][y] == ".": + if x == 0 or x == m - 1 or y == 0 or y == n - 1: + return ans + q.append((x, y)) + maze[x][y] = "+" + return -1 +``` + +#### Java + +```java +class Solution { + public int nearestExit(char[][] maze, int[] entrance) { + int m = maze.length, n = maze[0].length; + final int[] dirs = {-1, 0, 1, 0, -1}; + Deque q = new ArrayDeque<>(); + q.offer(entrance); + maze[entrance[0]][entrance[1]] = '+'; + for (int ans = 1; !q.isEmpty(); ++ans) { + for (int k = q.size(); k > 0; --k) { + var p = q.poll(); + for (int d = 0; d < 4; ++d) { + int x = p[0] + dirs[d], y = p[1] + dirs[d + 1]; + if (x >= 0 && x < m && y >= 0 && y < n && maze[x][y] == '.') { + if (x == 0 || x == m - 1 || y == 0 || y == n - 1) { + return ans; + } + maze[x][y] = '+'; + q.offer(new int[] {x, y}); + } + } + } + } + return -1; + } +} +``` + +#### C++ + +```cpp +#include +#include +using namespace std; + +class Solution { +public: + int nearestExit(vector>& maze, vector& entrance) { + int m = maze.size(), n = maze[0].size(); + int dirs[5] = {-1, 0, 1, 0, -1}; + queue> q; + + + q.push({entrance[0], entrance[1]}); + maze[entrance[0]][entrance[1]] = '+'; + for (int ans = 1; !q.empty(); ++ans) { + for (int sz = q.size(); sz > 0; --sz) { + auto [x, y] = q.front(); + q.pop(); + for (int d = 0; d < 4; ++d) { + int nx = x + dirs[d], ny = y + dirs[d + 1]; + if (nx >= 0 && nx < m && ny >= 0 && ny < n && maze[nx][ny] == '.') { + if (nx == 0 || nx == m - 1 || ny == 0 || ny == n - 1) { + return ans; + } + maze[nx][ny] = '+'; + q.push({nx, ny}); + } + } + } + } + return -1; + } +}; +``` + +#### Go + +```go +import "container/list" + +func nearestExit(maze [][]byte, entrance []int) int { + dirs := []int{-1, 0, 1, 0, -1} + m, n := len(maze), len(maze[0]) + queue := list.New() + queue.PushBack(entrance) + maze[entrance[0]][entrance[1]] = '+' + for steps := 1; queue.Len() > 0; steps++ { + for sz := queue.Len(); sz > 0; sz-- { + p := queue.Remove(queue.Front()).([2]int) + for d := 0; d < 4; d++ { + x, y := p[0]+dirs[d], p[1]+dirs[d+1] + if x >= 0 && x < m && y >= 0 && y < n && maze[x][y] == '.' { + if x == 0 || x == m-1 || y == 0 || y == n-1 { + return steps + } + maze[x][y] = '+' + queue.PushBack([2]int{x, y}) + } + } + } + } + return -1 +} +``` + +#### TypeScript + +```typescript +function nearestExit(maze: string[][], entrance: number[]): number { + const dirs = [-1, 0, 1, 0, -1]; + const m = maze.length, n = maze[0].length; + const queue: number[][] = [entrance]; + maze[entrance[0]][entrance[1]] = '+'; + for (let ans = 1; queue.length > 0; ++ans) { + for (let sz = queue.length; sz > 0; --sz) { + const [x, y] = queue.shift()!; + for (let d = 0; d < 4; ++d) { + const nx = x + dirs[d], ny = y + dirs[d + 1]; + if (nx >= 0 && nx < m && ny >= 0 && ny < n && maze[nx][ny] === '.') { + if (nx === 0 || nx === m - 1 || ny === 0 || ny === n - 1) { + return ans; + } + maze[nx][ny] = '+'; + queue.push([nx, ny]); + } + } + } + } + return -1; +} +``` + + + +## Related Topics +- Breadth-First Search +- Array +- Matrix + +## Similar Problems +- [542. 01 Matrix](https://leetcode.com/problems/01-matrix/) +- [1091. Shortest Path in Binary Matrix](https://leetcode.com/problems/shortest-path-in-binary-matrix/) +- [1094. Car Pooling](https://leetcode.com/problems/car-pooling/) + + diff --git a/Solution/215. Kth Largest Element in an Array/215. Kth Largest Element in an Array.py b/Solution/215. Kth Largest Element in an Array/215. Kth Largest Element in an Array.py new file mode 100644 index 0000000..3a7d1cd --- /dev/null +++ b/Solution/215. Kth Largest Element in an Array/215. Kth Largest Element in an Array.py @@ -0,0 +1,25 @@ +class Solution: + def findKthLargest(self, nums: List[int], k: int) -> int: + def quick_sort(l: int, r: int) -> int: + if l == r: + return nums[l] + i, j = l - 1, r + 1 + x = nums[(l + r) >> 1] + while i < j: + while 1: + i += 1 + if nums[i] >= x: + break + while 1: + j -= 1 + if nums[j] <= x: + break + if i < j: + nums[i], nums[j] = nums[j], nums[i] + if j < k: + return quick_sort(j + 1, r) + return quick_sort(l, j) + + n = len(nums) + k = n - k + return quick_sort(0, n - 1) \ No newline at end of file diff --git a/Solution/215. Kth Largest Element in an Array/readme.md b/Solution/215. Kth Largest Element in an Array/readme.md new file mode 100644 index 0000000..725c874 --- /dev/null +++ b/Solution/215. Kth Largest Element in an Array/readme.md @@ -0,0 +1,156 @@ + +# 215. Kth Largest Element in an Array + +>**Difficulty**: Medium +> **Tag**: `Array`, `Heap (Priority Queue)`, `Divide and Conquer`, `Quickselect`, `Sorting` + +## Description + +Given an integer array `nums` and an integer `k`, return the `k`th largest element in the array. + +Note that it is the `k`th largest element in the sorted order, not the `k`th distinct element. + +You must solve it in `O(n)` time complexity on average. + +## Example + +**Example 1:** + +``` +Input: nums = [3,2,1,5,6,4], k = 2 +Output: 5 +``` + +**Example 2:** + +``` +Input: nums = [3,2,3,1,2,4,5,5,6], k = 4 +Output: 4 +``` + +## Constraints + +- `1 <= k <= nums.length <= 10⁡` +- `-10⁴ <= nums[i] <= 10⁴` + +--- + +## Solutions + +### 🟦 Python + +```python +import heapq + +class Solution: + def findKthLargest(self, nums: List[int], k: int) -> int: + return heapq.nlargest(k, nums)[-1] +``` + +### β˜• Java + +```java +import java.util.PriorityQueue; + +class Solution { + public int findKthLargest(int[] nums, int k) { + PriorityQueue heap = new PriorityQueue<>(); + for (int num : nums) { + heap.offer(num); + if (heap.size() > k) { + heap.poll(); + } + } + return heap.peek(); + } +} +``` + +### πŸ’» C++ + +```cpp +#include +#include +using namespace std; + +class Solution { +public: + int findKthLargest(vector& nums, int k) { + priority_queue, greater> minHeap; + for (int num : nums) { + minHeap.push(num); + if (minHeap.size() > k) { + minHeap.pop(); + } + } + return minHeap.top(); + } +}; +``` + +### 🐹 Go + +```go +import "container/heap" + +type IntHeap []int + +func (h IntHeap) Len() int { return len(h) } +func (h IntHeap) Less(i, j int) bool { return h[i] < h[j] } +func (h IntHeap) Swap(i, j int) { h[i], h[j] = h[j], h[i] } +func (h *IntHeap) Push(x any) { *h = append(*h, x.(int)) } +func (h *IntHeap) Pop() (v any) { + n := len(*h) + *h, v = (*h)[:n-1], (*h)[n-1] + return +} + +func findKthLargest(nums []int, k int) int { + h := &IntHeap{} + for _, num := range nums { + heap.Push(h, num) + if h.Len() > k { + heap.Pop(h) + } + } + return (*h)[0] +} +``` + +### 🟨 TypeScript + +```ts +function findKthLargest(nums: number[], k: number): number { + const heap: number[] = []; + + for (let num of nums) { + heap.push(num); + heap.sort((a, b) => a - b); + if (heap.length > k) heap.shift(); + } + + return heap[0]; +} +``` + +### πŸ¦€ Rust + +```rust +use std::collections::BinaryHeap; +use std::cmp::Reverse; + +impl Solution { + pub fn find_kth_largest(nums: Vec, k: i32) -> i32 { + let mut heap = BinaryHeap::new(); + for &num in &nums { + heap.push(Reverse(num)); + if heap.len() > k as usize { + heap.pop(); + } + } + heap.peek().unwrap().0 + } +} +``` + +--- diff --git a/Solution/2300. Successful Pairs of Spells and Potions.py b/Solution/2300. Successful Pairs of Spells and Potions.py new file mode 100644 index 0000000..ded2efd --- /dev/null +++ b/Solution/2300. Successful Pairs of Spells and Potions.py @@ -0,0 +1,7 @@ +class Solution: + def successfulPairs( + self, spells: List[int], potions: List[int], success: int + ) -> List[int]: + potions.sort() + m = len(potions) + return [m - bisect_left(potions, success / v) for v in spells] \ No newline at end of file diff --git a/Solution/2336. Smallest Number in Infinite Set/2336. Smallest Number in Infinite Set.py b/Solution/2336. Smallest Number in Infinite Set/2336. Smallest Number in Infinite Set.py new file mode 100644 index 0000000..badee98 --- /dev/null +++ b/Solution/2336. Smallest Number in Infinite Set/2336. Smallest Number in Infinite Set.py @@ -0,0 +1,17 @@ +class SmallestInfiniteSet: + def __init__(self): + self.s = SortedSet(range(1, 1001)) + + def popSmallest(self) -> int: + x = self.s[0] + self.s.remove(x) + return x + + def addBack(self, num: int) -> None: + self.s.add(num) + + +# Your SmallestInfiniteSet object will be instantiated and called as such: +# obj = SmallestInfiniteSet() +# param_1 = obj.popSmallest() +# obj.addBack(num) \ No newline at end of file diff --git a/Solution/2336. Smallest Number in Infinite Set/readme.md b/Solution/2336. Smallest Number in Infinite Set/readme.md new file mode 100644 index 0000000..95e889a --- /dev/null +++ b/Solution/2336. Smallest Number in Infinite Set/readme.md @@ -0,0 +1,246 @@ + +# 2336. Smallest Number in Infinite Set +--- +## Description + +You have a set which contains all positive integers `[1, 2, 3, 4, 5, ...]`. + +Implement the `SmallestInfiniteSet` class: + +- `SmallestInfiniteSet()` Initializes the `SmallestInfiniteSet` object to contain all positive integers. +- `int popSmallest()` Removes and returns the smallest integer contained in the infinite set. +- `void addBack(int num)` Adds a positive integer `num` back into the infinite set, if it is not already in the infinite set. + +### Example 1: + +``` +Input +["SmallestInfiniteSet", "addBack", "popSmallest", "popSmallest", "popSmallest", "addBack", "popSmallest", "popSmallest", "popSmallest"] +[[], [2], [], [], [], [1], [], [], []] +Output +[null, null, 1, 2, 3, null, 1, 4, 5] +``` + +**Explanation** + +```python +SmallestInfiniteSet smallestInfiniteSet = new SmallestInfiniteSet(); +smallestInfiniteSet.addBack(2); # 2 is already in the set, so no change is made. +smallestInfiniteSet.popSmallest(); # return 1, and remove it from the set +smallestInfiniteSet.popSmallest(); # return 2, and remove it from the set +smallestInfiniteSet.popSmallest(); # return 3, and remove it from the set +smallestInfiniteSet.addBack(1); # 1 is added back to the set +smallestInfiniteSet.popSmallest(); # return 1, and remove it from the set +smallestInfiniteSet.popSmallest(); # return 4, and remove it from the set +smallestInfiniteSet.popSmallest(); # return 5, and remove it from the set +``` + +## Constraints + +- `1 <= num <= 1000` +- At most `1000` calls will be made in total to `popSmallest` and `addBack`. + +--- + +## Solutions + +### 🧠 Solution 1: Min Heap + Set + +We simulate the infinite set using: + +- A variable `current` which tracks the next number not yet popped (starting from 1). +- A min-heap `heap` for any added-back elements smaller than `current`. +- A set `in_heap` to avoid duplicate elements in the heap. + +### Python + +```python +import heapq + +class SmallestInfiniteSet: + def __init__(self): + self.current = 1 + self.heap = [] + self.in_heap = set() + + def popSmallest(self) -> int: + if self.heap: + smallest = heapq.heappop(self.heap) + self.in_heap.remove(smallest) + return smallest + else: + res = self.current + self.current += 1 + return res + + def addBack(self, num: int) -> None: + if num < self.current and num not in self.in_heap: + heapq.heappush(self.heap, num) + self.in_heap.add(num) +``` + +### Java + +```java +import java.util.*; + +class SmallestInfiniteSet { + private int current; + private PriorityQueue heap; + private Set set; + + public SmallestInfiniteSet() { + current = 1; + heap = new PriorityQueue<>(); + set = new HashSet<>(); + } + + public int popSmallest() { + if (!heap.isEmpty()) { + int smallest = heap.poll(); + set.remove(smallest); + return smallest; + } + return current++; + } + + public void addBack(int num) { + if (num < current && !set.contains(num)) { + heap.offer(num); + set.add(num); + } + } +} +``` + +### C++ + +```cpp +#include +#include +#include + +class SmallestInfiniteSet { +private: + int current; + priority_queue, greater> heap; + unordered_set in_heap; + +public: + SmallestInfiniteSet() { + current = 1; + } + + int popSmallest() { + if (!heap.empty()) { + int res = heap.top(); + heap.pop(); + in_heap.erase(res); + return res; + } + return current++; + } + + void addBack(int num) { + if (num < current && !in_heap.count(num)) { + heap.push(num); + in_heap.insert(num); + } + } +}; +``` + +### Go + +```go +import ( + "container/heap" +) + +type SmallestInfiniteSet struct { + current int + pq IntHeap + inHeap map[int]bool +} + +func Constructor() SmallestInfiniteSet { + return SmallestInfiniteSet{current: 1, inHeap: make(map[int]bool)} +} + +func (this *SmallestInfiniteSet) PopSmallest() int { + if len(this.pq) > 0 { + smallest := heap.Pop(&this.pq).(int) + delete(this.inHeap, smallest) + return smallest + } + this.current++ + return this.current - 1 +} + +func (this *SmallestInfiniteSet) AddBack(num int) { + if num < this.current && !this.inHeap[num] { + heap.Push(&this.pq, num) + this.inHeap[num] = true + } +} + +type IntHeap []int + +func (h IntHeap) Len() int { return len(h) } +func (h IntHeap) Less(i, j int) bool { return h[i] < h[j] } +func (h IntHeap) Swap(i, j int) { h[i], h[j] = h[j], h[i] } +func (h *IntHeap) Push(x interface{}) { *h = append(*h, x.(int)) } +func (h *IntHeap) Pop() interface{} { + old := *h + n := len(old) + val := old[n-1] + *h = old[:n-1] + return val +} +``` + +### TypeScript + +```ts +class SmallestInfiniteSet { + private current = 1; + private heap: number[] = []; + private inHeap = new Set(); + + popSmallest(): number { + if (this.heap.length > 0) { + const smallest = this.heap.shift()!; + this.inHeap.delete(smallest); + return smallest; + } + return this.current++; + } + + addBack(num: number): void { + if (num < this.current && !this.inHeap.has(num)) { + this.heap.push(num); + this.heap.sort((a, b) => a - b); + this.inHeap.add(num); + } + } +} +``` + +--- + +## Complexity Analysis + +| Operation | Time Complexity | Space Complexity | +|----------------|------------------|------------------| +| `popSmallest` | O(log n) | O(n) | +| `addBack` | O(log n) | O(n) | + +--- + +## Tags + +- πŸ”’ Heap (Priority Queue) +- πŸ“Š Simulation +- 🧠 Design +``` + diff --git a/Solution/2462. Total Cost to Hire K Workers/2462. Total Cost to Hire K Workers.py b/Solution/2462. Total Cost to Hire K Workers/2462. Total Cost to Hire K Workers.py new file mode 100644 index 0000000..84ac7ac --- /dev/null +++ b/Solution/2462. Total Cost to Hire K Workers/2462. Total Cost to Hire K Workers.py @@ -0,0 +1,25 @@ +class Solution: + def totalCost(self, costs: List[int], k: int, candidates: int) -> int: + n = len(costs) + if candidates * 2 >= n: + return sum(sorted(costs)[:k]) + pq = [] + for i, c in enumerate(costs[:candidates]): + heappush(pq, (c, i)) + for i in range(n - candidates, n): + heappush(pq, (costs[i], i)) + heapify(pq) + l, r = candidates, n - candidates - 1 + ans = 0 + for _ in range(k): + c, i = heappop(pq) + ans += c + if l > r: + continue + if i < l: + heappush(pq, (costs[l], l)) + l += 1 + else: + heappush(pq, (costs[r], r)) + r -= 1 + return ans \ No newline at end of file diff --git a/Solution/2462. Total Cost to Hire K Workers/readme.md b/Solution/2462. Total Cost to Hire K Workers/readme.md new file mode 100644 index 0000000..24edbba --- /dev/null +++ b/Solution/2462. Total Cost to Hire K Workers/readme.md @@ -0,0 +1,251 @@ + +# [2462. Total Cost to Hire K Workers](https://leetcode.com/problems/total-cost-to-hire-k-workers) +--- +- **comments**: true +- **difficulty**: Medium +- **edit_url**: https://github.com/doocs/leetcode/edit/main/solution/2400-2499/2462.Total%20Cost%20to%20Hire%20K%20Workers/README_EN.md +- **rating**: 1763 +- **source**: Weekly Contest 318 Q3 +- **tags**: + - Array + - Two Pointers + - Simulation + - Heap (Priority Queue) +--- + +## Description + + + +

You are given a 0-indexed integer array costs where costs[i] is the cost of hiring the ith worker.

+ +

You are also given two integers k and candidates. We want to hire exactly k workers according to the following rules:

+ +
    +
  • You will run k sessions and hire exactly one worker in each session.
  • +
  • In each hiring session, choose the worker with the lowest cost from either the first candidates workers or the last candidates workers. Break the tie by the smallest index.
  • +
  • If there are fewer than candidates workers remaining, choose the worker with the lowest cost among them. Break the tie by the smallest index.
  • +
  • A worker can only be chosen once.
  • +
+ +

Return the total cost to hire exactly k workers.

+ +

 

+

Example 1:

+ +
+Input: costs = [17,12,10,2,7,2,11,20,8], k = 3, candidates = 4
+Output: 11
+Explanation: We hire 3 workers in total. The total cost is initially 0.
+- In the first hiring round we choose the worker from [17,12,10,2,7,2,11,20,8]. The lowest cost is 2, and we break the tie by the smallest index, which is 3. The total cost = 0 + 2 = 2.
+- In the second hiring round we choose the worker from [17,12,10,7,2,11,20,8]. The lowest cost is 2 (index 4). The total cost = 2 + 2 = 4.
+- In the third hiring round we choose the worker from [17,12,10,7,11,20,8]. The lowest cost is 7 (index 3). The total cost = 4 + 7 = 11.
+The total hiring cost is 11.
+
+ +

Example 2:

+ +
+Input: costs = [1,2,4,1], k = 3, candidates = 3
+Output: 4
+Explanation: We hire 3 workers in total. The total cost is initially 0.
+- In the first hiring round we choose the worker from [1,2,4,1]. The lowest cost is 1, and we break the tie by the smallest index, which is 0. The total cost = 0 + 1 = 1.
+- In the second hiring round we choose the worker from [2,4,1]. The lowest cost is 1 (index 2). The total cost = 1 + 1 = 2.
+- In the third hiring round there are less than three candidates. We choose the worker from the remaining workers [2,4]. The lowest cost is 2 (index 0). The total cost = 2 + 2 = 4.
+The total hiring cost is 4.
+
+ +

 

+

Constraints:

+ +
    +
  • 1 <= costs.length <= 105
  • +
  • 1 <= costs[i] <= 105
  • +
  • 1 <= k, candidates <= costs.length
  • +
+ + + +## Solutions + + + +### Solution 1: Priority Queue (Min Heap) + +First, we check if $candidates \times 2$ is greater than or equal to $n$. If it is, we directly return the sum of the costs of the first $k$ smallest workers. + +Otherwise, we use a min heap $pq$ to maintain the costs of the first $candidates$ workers and the last $candidates$ workers. + +We first add the costs and corresponding indices of the first $candidates$ workers to the min heap $pq$, and then add the costs and corresponding indices of the last $candidates$ workers to the min heap $pq$. We use two pointers $l$ and $r$ to point to the indices of the front and back candidates, initially $l = candidates$, $r = n - candidates - 1$. + +Then we perform $k$ iterations, each time taking the worker with the smallest cost from the min heap $pq$ and adding its cost to the answer. If $l > r$, it means that all the front and back candidates have been selected, and we skip directly. Otherwise, if the index of the current worker is less than $l$, it means it is a worker from the front, we add the cost and index of the $l$-th worker to the min heap $pq$, and then increment $l$; otherwise, we add the cost and index of the $r$-th worker to the min heap $pq$, and then decrement $r$. + +After the loop ends, we return the answer. + +The time complexity is $O(n \times \log n)$, and the space complexity is $O(n)$. Where $n$ is the length of the array $costs$. + + + +#### Python3 + +```python +class Solution: + def totalCost(self, costs: List[int], k: int, candidates: int) -> int: + n = len(costs) + if candidates * 2 >= n: + return sum(sorted(costs)[:k]) + pq = [] + for i, c in enumerate(costs[:candidates]): + heappush(pq, (c, i)) + for i in range(n - candidates, n): + heappush(pq, (costs[i], i)) + heapify(pq) + l, r = candidates, n - candidates - 1 + ans = 0 + for _ in range(k): + c, i = heappop(pq) + ans += c + if l > r: + continue + if i < l: + heappush(pq, (costs[l], l)) + l += 1 + else: + heappush(pq, (costs[r], r)) + r -= 1 + return ans +``` + +#### Java + +```java +class Solution { + public long totalCost(int[] costs, int k, int candidates) { + int n = costs.length; + long ans = 0; + if (candidates * 2 >= n) { + Arrays.sort(costs); + for (int i = 0; i < k; ++i) { + ans += costs[i]; + } + return ans; + } + PriorityQueue pq + = new PriorityQueue<>((a, b) -> a[0] == b[0] ? a[1] - b[1] : a[0] - b[0]); + for (int i = 0; i < candidates; ++i) { + pq.offer(new int[] {costs[i], i}); + pq.offer(new int[] {costs[n - i - 1], n - i - 1}); + } + int l = candidates, r = n - candidates - 1; + while (k-- > 0) { + var p = pq.poll(); + ans += p[0]; + if (l > r) { + continue; + } + if (p[1] < l) { + pq.offer(new int[] {costs[l], l++}); + } else { + pq.offer(new int[] {costs[r], r--}); + } + } + return ans; + } +} +``` + +#### C++ + +```cpp +class Solution { +public: + long long totalCost(vector& costs, int k, int candidates) { + int n = costs.size(); + if (candidates * 2 > n) { + sort(costs.begin(), costs.end()); + return accumulate(costs.begin(), costs.begin() + k, 0LL); + } + using pii = pair; + priority_queue, greater> pq; + for (int i = 0; i < candidates; ++i) { + pq.emplace(costs[i], i); + pq.emplace(costs[n - i - 1], n - i - 1); + } + long long ans = 0; + int l = candidates, r = n - candidates - 1; + while (k--) { + auto [cost, i] = pq.top(); + pq.pop(); + ans += cost; + if (l > r) { + continue; + } + if (i < l) { + pq.emplace(costs[l], l++); + } else { + pq.emplace(costs[r], r--); + } + } + return ans; + } +}; +``` + +#### Go + +```go +func totalCost(costs []int, k int, candidates int) (ans int64) { + n := len(costs) + if candidates*2 > n { + sort.Ints(costs) + for _, x := range costs[:k] { + ans += int64(x) + } + return + } + pq := hp{} + for i, x := range costs[:candidates] { + heap.Push(&pq, pair{x, i}) + heap.Push(&pq, pair{costs[n-i-1], n - i - 1}) + } + l, r := candidates, n-candidates-1 + for ; k > 0; k-- { + p := heap.Pop(&pq).(pair) + ans += int64(p.cost) + if l > r { + continue + } + if p.i < l { + heap.Push(&pq, pair{costs[l], l}) + l++ + } else { + heap.Push(&pq, pair{costs[r], r}) + r-- + } + } + return +} + +type pair struct{ cost, i int } +type hp []pair + +func (h hp) Len() int { return len(h) } +func (h hp) Less(i, j int) bool { + return h[i].cost < h[j].cost || (h[i].cost == h[j].cost && h[i].i < h[j].i) +} +func (h hp) Swap(i, j int) { h[i], h[j] = h[j], h[i] } +func (h *hp) Push(v any) + + { *h = append(*h, v.(pair)) } +func (h *hp) Pop() any { + old := *h + n := len(old) + x := old[n-1] + *h = old[:n-1] + return x +} +``` + + + + diff --git a/Solution/2542. Maximum Subsequence Score/2542. Maximum Subsequence Score.py b/Solution/2542. Maximum Subsequence Score/2542. Maximum Subsequence Score.py new file mode 100644 index 0000000..9837659 --- /dev/null +++ b/Solution/2542. Maximum Subsequence Score/2542. Maximum Subsequence Score.py @@ -0,0 +1,15 @@ +from heapq import heappush, heappop +from typing import List + +class Solution: + def maxScore(self, nums1: List[int], nums2: List[int], k: int) -> int: + nums = sorted(zip(nums2, nums1), reverse=True) + q = [] + ans = s = 0 + for a, b in nums: + s += b + heappush(q, b) + if len(q) == k: + ans = max(ans, s * a) + s -= heappop(q) + return ans \ No newline at end of file diff --git a/Solution/2542. Maximum Subsequence Score/readme.md b/Solution/2542. Maximum Subsequence Score/readme.md new file mode 100644 index 0000000..e51f286 --- /dev/null +++ b/Solution/2542. Maximum Subsequence Score/readme.md @@ -0,0 +1,186 @@ + +# [2542. Maximum Subsequence Score](https://leetcode.com/problems/maximum-subsequence-score) + + +--- +- **comments**: true +- **difficulty**: Medium +- **edit_url**: https://github.com/doocs/leetcode/edit/main/solution/2500-2599/2542.Maximum%20Subsequence%20Score/README_EN.md +- **rating**: 2056 +- **source**: Biweekly Contest 96 Q3 +- **tags**: + - Greedy + - Array + - Sorting + - Heap (Priority Queue) +--- +## Description + +

You are given two 0-indexed integer arrays nums1 and nums2 of equal length n and a positive integer k. You must choose a subsequence of indices from nums1 of length k.

+ +

For chosen indices i0, i1, ..., ik - 1, your score is defined as:

+ +
    +
  • The sum of the selected elements from nums1 multiplied with the minimum of the selected elements from nums2.
  • +
  • It can be defined simply as: (nums1[i0] + nums1[i1] +...+ nums1[ik - 1]) * min(nums2[i0] , nums2[i1], ... ,nums2[ik - 1]).
  • +
+ +

Return the maximum possible score.

+ +

A subsequence of indices of an array is a set that can be derived from the set {0, 1, ..., n-1} by deleting some or no elements.

+ +

 

+

Example 1:

+ +
+Input: nums1 = [1,3,3,2], nums2 = [2,1,3,4], k = 3
+Output: 12
+Explanation: 
+The four possible subsequence scores are:
+- We choose the indices 0, 1, and 2 with score = (1+3+3) * min(2,1,3) = 7.
+- We choose the indices 0, 1, and 3 with score = (1+3+2) * min(2,1,4) = 6. 
+- We choose the indices 0, 2, and 3 with score = (1+3+2) * min(2,3,4) = 12. 
+- We choose the indices 1, 2, and 3 with score = (3+3+2) * min(1,3,4) = 8.
+Therefore, we return the max score, which is 12.
+
+ +

Example 2:

+ +
+Input: nums1 = [4,2,3,1,1], nums2 = [7,5,10,9,6], k = 1
+Output: 30
+Explanation: 
+Choosing index 2 is optimal: nums1[2] * nums2[2] = 3 * 10 = 30 is the maximum possible score.
+
+ +

 

+

Constraints:

+ +
    +
  • n == nums1.length == nums2.length
  • +
  • 1 <= n <= 105
  • +
  • 0 <= nums1[i], nums2[j] <= 105
  • +
  • 1 <= k <= n
  • +
+ + + +## Solutions + +### Solution 1: Sorting + Priority Queue (Min Heap) + +Sort nums2 and nums1 in descending order according to nums2, then traverse from front to back, maintaining a min heap. The heap stores elements from nums1, and the number of elements in the heap does not exceed $k$. At the same time, maintain a variable $s$ representing the sum of the elements in the heap, and continuously update the answer during the traversal process. + +The time complexity is $O(n \times \log n)$, and the space complexity is $O(n)$. Here, $n$ is the length of the array nums1. + + + +#### Python3 + +```python +class Solution: + def maxScore(self, nums1: List[int], nums2: List[int], k: int) -> int: + nums = sorted(zip(nums2, nums1), reverse=True) + q = [] + ans = s = 0 + for a, b in nums: + s += b + heappush(q, b) + if len(q) == k: + ans = max(ans, s * a) + s -= heappop(q) + return ans +``` + +#### Java + +```java +class Solution { + public long maxScore(int[] nums1, int[] nums2, int k) { + int n = nums1.length; + int[][] nums = new int[n][2]; + for (int i = 0; i < n; ++i) { + nums[i] = new int[] {nums1[i], nums2[i]}; + } + Arrays.sort(nums, (a, b) -> b[1] - a[1]); + long ans = 0, s = 0; + PriorityQueue q = new PriorityQueue<>(); + for (int i = 0; i < n; ++i) { + s += nums[i][0]; + q.offer(nums[i][0]); + if (q.size() == k) { + ans = Math.max(ans, s * nums[i][1]); + s -= q.poll(); + } + } + return ans; + } +} +``` + +#### C++ + +```cpp +class Solution { +public: + long long maxScore(vector& nums1, vector& nums2, int k) { + int n = nums1.size(); + vector> nums(n); + for (int i = 0; i < n; ++i) { + nums[i] = {-nums2[i], nums1[i]}; + } + sort(nums.begin(), nums.end()); + priority_queue, greater> q; + long long ans = 0, s = 0; + for (auto& [a, b] : nums) { + s += b; + q.push(b); + if (q.size() == k) { + ans = max(ans, s * -a); + s -= q.top(); + q.pop(); + } + } + return ans; + } +}; +``` + +#### Go + +```go +func maxScore(nums1 []int, nums2 []int, k int) int64 { + type pair struct{ a, b int } + nums := []pair{} + for i, a := range nums1 { + b := nums2[i] + nums = append(nums, pair{a, b}) + } + sort.Slice(nums, func(i, j int) bool { return nums[i].b > nums[j].b }) + q := hp{} + var ans, s int + for _, e := range nums { + a, b := e.a, e.b + s += a + heap.Push(&q, a) + if q.Len() == k { + ans = max(ans, s*b) + s -= heap.Pop(&q).(int) + } + } + return int64(ans) +} + +type hp struct{ sort.IntSlice } + +func (h hp) Less(i, j int) bool { return h.IntSlice[i] < h.IntSlice[j] } +func (h *hp) Push(v any) { h.IntSlice = append(h.IntSlice, v.(int)) } +func (h *hp) Pop() any { + a := h.IntSlice + v := a[len(a)-1] + h.IntSlice = a[:len(a)-1] + return v +} +``` + + diff --git a/Solution/374. Guess Number Higher or Lower/374. Guess Number Higher or Lower.py b/Solution/374. Guess Number Higher or Lower/374. Guess Number Higher or Lower.py new file mode 100644 index 0000000..934a98d --- /dev/null +++ b/Solution/374. Guess Number Higher or Lower/374. Guess Number Higher or Lower.py @@ -0,0 +1,11 @@ +# The guess API is already defined for you. +# @param num, your guess +# @return -1 if num is higher than the picked number +# 1 if num is lower than the picked number +# otherwise return 0 +# def guess(num: int) -> int: + + +class Solution: + def guessNumber(self, n: int) -> int: + return bisect.bisect(range(1, n + 1), 0, key=lambda x: -guess(x)) \ No newline at end of file diff --git a/Solution/374. Guess Number Higher or Lower/readme.md b/Solution/374. Guess Number Higher or Lower/readme.md new file mode 100644 index 0000000..3ad09c9 --- /dev/null +++ b/Solution/374. Guess Number Higher or Lower/readme.md @@ -0,0 +1,288 @@ + +# [374. Guess Number Higher or Lower](https://leetcode.com/problems/guess-number-higher-or-lower) +--- +- **comments**: true +- **difficulty**: Easy +- **edit_url**: https://github.com/doocs/leetcode/edit/main/solution/0300-0399/0374.Guess%20Number%20Higher%20or%20Lower/README_EN.md +- **tags**: + - Binary Search + - Interactive +--- + + +## Description + + + +

We are playing the Guess Game. The game is as follows:

+ +

I pick a number from 1 to n. You have to guess which number I picked.

+ +

Every time you guess wrong, I will tell you whether the number I picked is higher or lower than your guess.

+ +

You call a pre-defined API int guess(int num), which returns three possible results:

+ +
    +
  • -1: Your guess is higher than the number I picked (i.e. num > pick).
  • +
  • 1: Your guess is lower than the number I picked (i.e. num < pick).
  • +
  • 0: your guess is equal to the number I picked (i.e. num == pick).
  • +
+ +

Return the number that I picked.

+ +

 

+

Example 1:

+ +
+Input: n = 10, pick = 6
+Output: 6
+
+ +

Example 2:

+ +
+Input: n = 1, pick = 1
+Output: 1
+
+ +

Example 3:

+ +
+Input: n = 2, pick = 1
+Output: 1
+
+ +

 

+

Constraints:

+ +
    +
  • 1 <= n <= 231 - 1
  • +
  • 1 <= pick <= n
  • +
+ + + +## Solutions + + + +### Solution 1: Binary Search + +We perform a binary search in the interval $[1,..n]$, and find the first number that satisfies `guess(x) <= 0`, which is the answer. + +The time complexity is $O(\log n)$, where $n$ is the upper limit given in the problem. The space complexity is $O(1)$. + + + +#### Python3 + +```python +# The guess API is already defined for you. +# @param num, your guess +# @return -1 if num is higher than the picked number +# 1 if num is lower than the picked number +# otherwise return 0 +# def guess(num: int) -> int: + + +class Solution: + def guessNumber(self, n: int) -> int: + left, right = 1, n + while left < right: + mid = (left + right) // 2 + if guess(mid) == 0: + return mid + elif guess(mid) == -1: + right = mid - 1 + else: + left = mid + 1 + return left +``` + +#### Java + +```java +/** + * Forward declaration of guess API. + * @param num your guess + * @return -1 if num is lower than the guess number + * 1 if num is higher than the guess number + * otherwise return 0 + * int guess(int num); + */ + +public class Solution extends GuessGame { + public int guessNumber(int n) { + int left = 1, right = n; + while (left < right) { + int mid = (left + right) >>> 1; + if (guess(mid) == 0) { + return mid; + } else if (guess(mid) == -1) { + right = mid - 1; + } else { + left = mid + 1; + } + } + return left; + } +} +``` + +#### C++ + +```cpp +/** + * Forward declaration of guess API. + * @param num your guess + * @return -1 if num is lower than the guess number + * 1 if num is higher than the guess number + * otherwise return 0 + * int guess(int num); + */ + +class Solution { +public: + int guessNumber(int n) { + int left = 1, right = n; + while (left < right) { + int mid = left + ((right - left) >> 1); + if (guess(mid) == 0) { + return mid; + } else if (guess(mid) == -1) { + right = mid - 1; + } else { + left = mid + 1; + } + } + return left; + } +}; +``` + +#### Go + +```go +/** + * Forward declaration of guess API. + * @param num your guess + * @return -1 if num is higher than the picked number + * 1 if num is lower than the picked number + * otherwise return 0 + * func guess(num int) int; + */ + +func guessNumber(n int) int { + left, right := 1, n + for left < right { + mid := (left + right) / 2 + if guess(mid) == 0 { + return mid + } else if guess(mid) == -1 { + right = mid - 1 + } else { + left = mid + 1 + } + } + return left +} +``` + +#### TypeScript + +```ts +/** + * Forward declaration of guess API. + * @param {number} num your guess + * @return -1 if num is lower than the guess number + * 1 if num is higher than the guess number + * otherwise return 0 + * var guess = function(num) {} + */ + +function guessNumber(n: number): number { + let left = 1, right = n; + while (left < right) { + const mid = (left + right) >>> 1; + if (guess(mid) == 0) { + return mid; + } else if (guess(mid) == -1) { + right = mid - 1; + } else { + left = mid + 1; + } + } + return left; +} +``` + +#### Rust + +```rust +/** + * Forward declaration of guess API. + * @param num your guess + * @return -1 if num is lower than the guess number + * 1 if num is higher than the guess number + * otherwise return 0 + * unsafe fn guess(num: i32) -> i32 {} + */ + +impl Solution { + unsafe fn guessNumber(n: i32) -> i32 { + let mut left = 1; + let mut right = n; + loop { + let mid = left + (right - left) / 2; + match guess(mid) { + -1 => { + right = mid - 1; + } + 1 => { + left = mid + 1; + } + _ => { + break mid; + } + } + } + } +} +``` + +#### C# + +```cs +/** + * Forward declaration of guess API. + * @param num your guess + * @return -1 if num is higher than the picked number + * 1 if num is lower than the picked number + * otherwise return 0 + * int guess(int num); + */ + +public class Solution : GuessGame { + public int GuessNumber(int n) { + int left = 1, right = n; + while (left < right) { + int mid = left + ((right - left) >> 1); + if (guess(mid) == 0) { + return mid; + } else if (guess(mid) == -1) { + right = mid - 1; + } else { + left = mid + 1; + } + } + return left; + } +} +``` + + + + + + +``` \ No newline at end of file diff --git a/Solution/399. Evaluate Division/399. Evaluate Division.py b/Solution/399. Evaluate Division/399. Evaluate Division.py new file mode 100644 index 0000000..d980e65 --- /dev/null +++ b/Solution/399. Evaluate Division/399. Evaluate Division.py @@ -0,0 +1,26 @@ +class Solution: + def calcEquation( + self, equations: List[List[str]], values: List[float], queries: List[List[str]] + ) -> List[float]: + def find(x): + if p[x] != x: + origin = p[x] + p[x] = find(p[x]) + w[x] *= w[origin] + return p[x] + + w = defaultdict(lambda: 1) + p = defaultdict() + for a, b in equations: + p[a], p[b] = a, b + for i, v in enumerate(values): + a, b = equations[i] + pa, pb = find(a), find(b) + if pa == pb: + continue + p[pa] = pb + w[pa] = w[b] * v / w[a] + return [ + -1 if c not in p or d not in p or find(c) != find(d) else w[c] / w[d] + for c, d in queries + ] \ No newline at end of file diff --git a/Solution/399. Evaluate Division/readme.md b/Solution/399. Evaluate Division/readme.md new file mode 100644 index 0000000..e6c6a05 --- /dev/null +++ b/Solution/399. Evaluate Division/readme.md @@ -0,0 +1,309 @@ + + + +# [399. Evaluate Division](https://leetcode.com/problems/evaluate-division) + +--- +- **comments**: true +- **difficulty**: Medium +- **edit_url**: https://github.com/doocs/leetcode/edit/main/solution/0300-0399/0399.Evaluate%20Division/README_EN.md +- **tags**: + - Depth-First Search + - Breadth-First Search + - Union Find + - Graph + - Array + - String + - Shortest Path +--- + +## Description + + + +

You are given an array of variable pairs equations and an array of real numbers values, where equations[i] = [Ai, Bi] and values[i] represent the equation Ai / Bi = values[i]. Each Ai or Bi is a string that represents a single variable.

+ +

You are also given some queries, where queries[j] = [Cj, Dj] represents the jth query where you must find the answer for Cj / Dj = ?.

+ +

Return the answers to all queries. If a single answer cannot be determined, return -1.0.

+ +

Note: The input is always valid. You may assume that evaluating the queries will not result in division by zero and that there is no contradiction.

+ +

Note: The variables that do not occur in the list of equations are undefined, so the answer cannot be determined for them.

+ +

 

+

Example 1:

+ +
+Input: equations = [["a","b"],["b","c"]], values = [2.0,3.0], queries = [["a","c"],["b","a"],["a","e"],["a","a"],["x","x"]]
+Output: [6.00000,0.50000,-1.00000,1.00000,-1.00000]
+Explanation: 
+Given: a / b = 2.0, b / c = 3.0
+queries are: a / c = ?, b / a = ?, a / e = ?, a / a = ?, x / x = ? 
+return: [6.0, 0.5, -1.0, 1.0, -1.0 ]
+note: x is undefined => -1.0
+ +

Example 2:

+ +
+Input: equations = [["a","b"],["b","c"],["bc","cd"]], values = [1.5,2.5,5.0], queries = [["a","c"],["c","b"],["bc","cd"],["cd","bc"]]
+Output: [3.75000,0.40000,5.00000,0.20000]
+
+ +

Example 3:

+ +
+Input: equations = [["a","b"]], values = [0.5], queries = [["a","b"],["b","a"],["a","c"],["x","y"]]
+Output: [0.50000,2.00000,-1.00000,-1.00000]
+
+ +

 

+

Constraints:

+ +
    +
  • 1 <= equations.length <= 20
  • +
  • equations[i].length == 2
  • +
  • 1 <= Ai.length, Bi.length <= 5
  • +
  • values.length == equations.length
  • +
  • 0.0 < values[i] <= 20.0
  • +
  • 1 <= queries.length <= 20
  • +
  • queries[i].length == 2
  • +
  • 1 <= Cj.length, Dj.length <= 5
  • +
  • Ai, Bi, Cj, Dj consist of lower case English letters and digits.
  • +
+ + + +## Solutions + + + +### Solution 1 + + + +#### Python3 + +```python +class Solution: + def calcEquation( + self, equations: List[List[str]], values: List[float], queries: List[List[str]] + ) -> List[float]: + def find(x): + if p[x] != x: + origin = p[x] + p[x] = find(p[x]) + w[x] *= w[origin] + return p[x] + + w = defaultdict(lambda: 1) + p = defaultdict() + for a, b in equations: + p[a], p[b] = a, b + for i, v in enumerate(values): + a, b = equations[i] + pa, pb = find(a), find(b) + if pa == pb: + continue + p[pa] = pb + w[pa] = w[b] * v / w[a] + return [ + -1 if c not in p or d not in p or find(c) != find(d) else w[c] / w[d] + for c, d in queries + ] +``` + +#### Java + +```java +class Solution { + private Map p; + private Map w; + + public double[] calcEquation( + List> equations, double[] values, List> queries) { + int n = equations.size(); + p = new HashMap<>(); + w = new HashMap<>(); + for (List e : equations) { + p.put(e.get(0), e.get(0)); + p.put(e.get(1), e.get(1)); + w.put(e.get(0), 1.0); + w.put(e.get(1), 1.0); + } + for (int i = 0; i < n; ++i) { + List e = equations.get(i); + String a = e.get(0), b = e.get(1); + String pa = find(a), pb = find(b); + if (Objects.equals(pa, pb)) { + continue; + } + p.put(pa, pb); + w.put(pa, w.get(b) * values[i] / w.get(a)); + } + int m = queries.size(); + double[] ans = new double[m]; + for (int i = 0; i < m; ++i) { + String c = queries.get(i).get(0), d = queries.get(i).get(1); + ans[i] = !p.containsKey(c) || !p.containsKey(d) || !Objects.equals(find(c), find(d)) + ? -1.0 + : w.get(c) / w.get(d); + } + return ans; + } + + private String find(String x) { + if (!Objects.equals(p.get(x), x)) { + String origin = p.get(x); + p.put(x, find(p.get(x))); + w.put(x, w.get(x) * w.get(origin)); + } + return p.get(x); + } +} +``` + +#### C++ + +```cpp +class Solution { +public: + unordered_map p; + unordered_map w; + + vector calcEquation(vector>& equations, vector& values, vector>& queries) { + int n = equations.size(); + for (auto e : equations) { + p[e[0]] = e[0]; + p[e[1]] = e[1]; + w[e[0]] = 1.0; + w[e[1]] = 1.0; + } + for (int i = 0; i < n; ++i) { + vector e = equations[i]; + string a = e[0], b = e[1]; + string pa = find(a), pb = find(b); + if (pa == pb) continue; + p[pa] = pb; + w[pa] = w[b] * values[i] / w[a]; + } + int m = queries.size(); + vector ans(m); + for (int i = 0; i < m; ++i) { + string c = queries[i][0], d = queries[i][1]; + ans[i] = p.find(c) == p.end() || p.find(d) == p.end() + + || find(c) != find(d) ? -1.0 : w[c] / w[d]; + } + return ans; + } + +private: + string find(string x) { + if (p[x] != x) { + string origin = p[x]; + p[x] = find(p[x]); + w[x] *= w[origin]; + } + return p[x]; + } +}; +``` + +#### Go + +```go +func calcEquation(equations [][]string, values []float64, queries [][]string) []float64 { + p := make(map[string]string) + w := make(map[string]float64) + for i := 0; i < len(equations); i++ { + a, b := equations[i][0], equations[i][1] + p[a], p[b] = a, b + w[a], w[b] = 1.0, 1.0 + } + for i, v := range values { + a, b := equations[i][0], equations[i][1] + pa, pb := find(a, p, w), find(b, p, w) + if pa == pb { + continue + } + p[pa] = pb + w[pa] = w[b] * v / w[a] + } + + res := make([]float64, len(queries)) + for i, q := range queries { + c, d := q[0], q[1] + if _, ok1 := p[c]; !ok1 || _, ok2 := p[d]; !ok2 || find(c, p, w) != find(d, p, w) { + res[i] = -1.0 + } else { + res[i] = w[c] / w[d] + } + } + return res +} + +func find(x string, p map[string]string, w map[string]float64) string { + if p[x] != x { + origin := p[x] + p[x] = find(p[x], p, w) + w[x] *= w[origin] + } + return p[x] +} +``` + +#### TypeScript + +```typescript +function calcEquation(equations: string[][], values: number[], queries: string[][]): number[] { + const p: { [key: string]: string } = {}; + const w: { [key: string]: number } = {}; + equations.forEach((eq, i) => { + const [a, b] = eq; + p[a] = a; + p[b] = b; + w[a] = 1; + w[b] = 1; + }); + + equations.forEach((eq, i) => { + const [a, b] = eq; + const pa = find(a, p, w); + const pb = find(b, p, w); + if (pa === pb) return; + p[pa] = pb; + w[pa] = w[b] * values[i] / w[a]; + }); + + return queries.map(([c, d]) => { + if (!p[c] || !p[d] || find(c, p, w) !== find(d, p, w)) { + return -1; + } + return w[c] / w[d]; + }); +} + +function find(x: string, p: { [key: string]: string }, w: { [key: string]: number }): string { + if (p[x] !== x) { + const origin = p[x]; + p[x] = find(p[x], p, w); + w[x] *= w[origin]; + } + return p[x]; +} +``` + + + +### Solution 2 + + + +#### Python3 + +```python +# Alternative Solution using DFS to traverse the graph +``` + + diff --git a/Solution/547. Number of Provinces/547. Number of Provinces.py b/Solution/547. Number of Provinces/547. Number of Provinces.py new file mode 100644 index 0000000..f680742 --- /dev/null +++ b/Solution/547. Number of Provinces/547. Number of Provinces.py @@ -0,0 +1,16 @@ +class Solution: + def findCircleNum(self, isConnected: List[List[int]]) -> int: + def dfs(i: int): + vis[i] = True + for j, x in enumerate(isConnected[i]): + if not vis[j] and x: + dfs(j) + + n = len(isConnected) + vis = [False] * n + ans = 0 + for i in range(n): + if not vis[i]: + dfs(i) + ans += 1 + return ans \ No newline at end of file diff --git a/Solution/547. Number of Provinces/readme.md b/Solution/547. Number of Provinces/readme.md new file mode 100644 index 0000000..f10581f --- /dev/null +++ b/Solution/547. Number of Provinces/readme.md @@ -0,0 +1,372 @@ +# 547. Number of Provinces +- **difficulty**: Medium +- **related**: [] +- **tags**: + - **Depth**-First Search + - **Breadth**-First Search + - **Union Find** + - **Graph** +--- + +## Description + +There are `n` cities. Some of them are connected, while some are not. If city `a` is connected directly with city `b`, and city `b` is connected directly with city `c`, then city `a` is connected indirectly with city `c`. + +A **province** is a group of directly or indirectly connected cities and no other cities outside of the group. + +You are given an `n x n` matrix `isConnected` where `isConnected[i][j] = 1` if the `i-th` city and the `j-th` city are directly connected, and `isConnected[i][j] = 0` otherwise. + +Return *the total number of **provinces***. + +## Examples + +**Example 1:** + +``` +Input: isConnected = [[1,1,0],[1,1,0],[0,0,1]] +Output: 2 +``` + +**Example 2:** + +``` +Input: isConnected = [[1,0,0],[0,1,0],[0,0,1]] +Output: 3 +``` + +## Constraints + +- `1 <= n <= 200` +- `n == isConnected.length` +- `n == isConnected[i].length` +- `isConnected[i][j]` is `1` or `0`. +- `isConnected[i][i] == 1` +- `isConnected[i][j] == isConnected[j][i]` + +## Solutions + +### Solution 1: DFS + +We maintain a visited array and perform DFS from each unvisited node, marking all reachable nodes as visited. Each DFS traversal corresponds to a new province. + +**Time Complexity:** O(nΒ²) +**Space Complexity:** O(n) + +#### Python + +```python +class Solution: + def findCircleNum(self, isConnected: List[List[int]]) -> int: + def dfs(i: int): + vis[i] = True + for j, x in enumerate(isConnected[i]): + if not vis[j] and x: + dfs(j) + + n = len(isConnected) + vis = [False] * n + ans = 0 + for i in range(n): + if not vis[i]: + dfs(i) + ans += 1 + return ans +``` + +#### Java + +```java +class Solution { + private int[][] g; + private boolean[] vis; + + public int findCircleNum(int[][] isConnected) { + g = isConnected; + int n = g.length; + vis = new boolean[n]; + int ans = 0; + for (int i = 0; i < n; ++i) { + if (!vis[i]) { + dfs(i); + ++ans; + } + } + return ans; + } + + private void dfs(int i) { + vis[i] = true; + for (int j = 0; j < g.length; ++j) { + if (!vis[j] && g[i][j] == 1) { + dfs(j); + } + } + } +} +``` + +#### C++ + +```cpp +class Solution { +public: + int findCircleNum(vector>& isConnected) { + int n = isConnected.size(); + int ans = 0; + vector vis(n, false); + function dfs = [&](int i) { + vis[i] = true; + for (int j = 0; j < n; ++j) { + if (!vis[j] && isConnected[i][j]) { + dfs(j); + } + } + }; + for (int i = 0; i < n; ++i) { + if (!vis[i]) { + dfs(i); + ++ans; + } + } + return ans; + } +}; +``` + +#### Go + +```go +func findCircleNum(isConnected [][]int) int { + n := len(isConnected) + vis := make([]bool, n) + var dfs func(int) + dfs = func(i int) { + vis[i] = true + for j, x := range isConnected[i] { + if !vis[j] && x == 1 { + dfs(j) + } + } + } + ans := 0 + for i := range vis { + if !vis[i] { + ans++ + dfs(i) + } + } + return ans +} +``` + +#### TypeScript + +```ts +function findCircleNum(isConnected: number[][]): number { + const n = isConnected.length; + const vis = Array(n).fill(false); + const dfs = (i: number) => { + vis[i] = true; + for (let j = 0; j < n; ++j) { + if (!vis[j] && isConnected[i][j]) { + dfs(j); + } + } + }; + let ans = 0; + for (let i = 0; i < n; ++i) { + if (!vis[i]) { + dfs(i); + ++ans; + } + } + return ans; +} +``` + +#### Rust + +```rust +impl Solution { + fn dfs(is_connected: &Vec>, vis: &mut Vec, i: usize) { + vis[i] = true; + for j in 0..is_connected.len() { + if !vis[j] && is_connected[i][j] == 1 { + Self::dfs(is_connected, vis, j); + } + } + } + + pub fn find_circle_num(is_connected: Vec>) -> i32 { + let n = is_connected.len(); + let mut vis = vec![false; n]; + let mut res = 0; + for i in 0..n { + if !vis[i] { + res += 1; + Self::dfs(&is_connected, &mut vis, i); + } + } + res + } +} +``` + +--- + +### Solution 2: Union-Find + +Use Union-Find to group connected cities. Initially each city is its own parent. Merge cities with direct connections and count the number of distinct roots. + +**Time Complexity:** O(nΒ² * Ξ±(n)) +**Space Complexity:** O(n) + +#### Python + +```python +class Solution: + def findCircleNum(self, isConnected: List[List[int]]) -> int: + def find(x): + if p[x] != x: + p[x] = find(p[x]) + return p[x] + + n = len(isConnected) + p = list(range(n)) + ans = n + for i in range(n): + for j in range(i + 1, n): + if isConnected[i][j]: + pa, pb = find(i), find(j) + if pa != pb: + p[pa] = pb + ans -= 1 + return ans +``` + +#### Java + +```java +class Solution { + private int[] p; + + public int findCircleNum(int[][] isConnected) { + int n = isConnected.length; + p = new int[n]; + for (int i = 0; i < n; ++i) { + p[i] = i; + } + int ans = n; + for (int i = 0; i < n; ++i) { + for (int j = i + 1; j < n; ++j) { + if (isConnected[i][j] == 1) { + int pa = find(i), pb = find(j); + if (pa != pb) { + p[pa] = pb; + --ans; + } + } + } + } + return ans; + } + + private int find(int x) { + if (p[x] != x) { + p[x] = find(p[x]); + } + return p[x]; + } +} +``` + +#### C++ + +```cpp +class Solution { +public: + int findCircleNum(vector>& isConnected) { + int n = isConnected.size(); + vector p(n); + iota(p.begin(), p.end(), 0); + function find = [&](int x) { + return p[x] == x ? x : p[x] = find(p[x]); + }; + int ans = n; + for (int i = 0; i < n; ++i) { + for (int j = i + 1; j < n; ++j) { + if (isConnected[i][j]) { + int pa = find(i), pb = find(j); + if (pa != pb) { + p[pa] = pb; + --ans; + } + } + } + } + return ans; + } +}; +``` + +#### Go + +```go +func findCircleNum(isConnected [][]int) int { + n := len(isConnected) + p := make([]int, n) + for i := range p { + p[i] = i + } + var find func(int) int + find = func(x int) int { + if p[x] != x { + p[x] = find(p[x]) + } + return p[x] + } + ans := n + for i := 0; i < n; i++ { + for j := i + 1; j < n; j++ { + if isConnected[i][j] == 1 { + pa, pb := find(i), find(j) + if pa != pb { + p[pa] = pb + ans-- + } + } + } + } + return ans +} +``` + +#### TypeScript + +```ts +function findCircleNum(isConnected: number[][]): number { + const n = isConnected.length; + const p: number[] = Array.from({ length: n }, (_, i) => i); + const find = (x: number): number => { + if (p[x] !== x) { + p[x] = find(p[x]); + } + return p[x]; + }; + let ans = n; + for (let i = 0; i < n; ++i) { + for (let j = i + 1; j < n; ++j) { + if (isConnected[i][j]) { + const pa = find(i), pb = find(j); + if (pa !== pb) { + p[pa] = pb; + --ans; + } + } + } + } + return ans; +} +``` + +--- diff --git a/Solution/994. Rotting Oranges/994. Rotting Oranges.py b/Solution/994. Rotting Oranges/994. Rotting Oranges.py new file mode 100644 index 0000000..ba3a766 --- /dev/null +++ b/Solution/994. Rotting Oranges/994. Rotting Oranges.py @@ -0,0 +1,26 @@ +class Solution: + def orangesRotting(self, grid: List[List[int]]) -> int: + m, n = len(grid), len(grid[0]) + cnt = 0 + q = deque() + for i, row in enumerate(grid): + for j, x in enumerate(row): + if x == 2: + q.append((i, j)) + elif x == 1: + cnt += 1 + ans = 0 + dirs = (-1, 0, 1, 0, -1) + while q and cnt: + ans += 1 + for _ in range(len(q)): + i, j = q.popleft() + for a, b in pairwise(dirs): + x, y = i + a, j + b + if 0 <= x < m and 0 <= y < n and grid[x][y] == 1: + grid[x][y] = 2 + q.append((x, y)) + cnt -= 1 + if cnt == 0: + return ans + return -1 if cnt else 0 \ No newline at end of file diff --git a/Solution/994. Rotting Oranges/readme.md b/Solution/994. Rotting Oranges/readme.md new file mode 100644 index 0000000..c1a7785 --- /dev/null +++ b/Solution/994. Rotting Oranges/readme.md @@ -0,0 +1,346 @@ + + + + + +# [994. Rotting Oranges](https://leetcode.com/problems/rotting-oranges) +--- +- **comments**: true +- **difficulty**: Medium +- **edit_url**: https://github.com/doocs/leetcode/edit/main/solution/0900-0999/0994.Rotting%20Oranges/README_EN.md +- **tags**: + - Breadth-First Search + - Array + - Matrix +--- + +## Description + +You are given an `m x n` grid where each cell can have one of three values: + +- `0` representing an empty cell, +- `1` representing a fresh orange, or +- `2` representing a rotten orange. + +Every minute, any fresh orange that is **4-directionally adjacent** to a rotten orange becomes rotten. + +Return *the minimum number of minutes that must elapse until no cell has a fresh orange*. If this is impossible, return `-1`. + +**Example 1:** + +![Example](https://fastly.jsdelivr.net/gh/doocs/leetcode@main/solution/0900-0999/0994.Rotting%20Oranges/images/oranges.png) + +``` +Input: grid = [[2,1,1],[1,1,0],[0,1,1]] +Output: 4 +``` + +**Example 2:** + +``` +Input: grid = [[2,1,1],[0,1,1],[1,0,1]] +Output: -1 +Explanation: The orange in the bottom left corner (row 2, column 0) is never rotten. +``` + +**Example 3:** + +``` +Input: grid = [[0,2]] +Output: 0 +Explanation: There are no fresh oranges to begin with. +``` + +**Constraints:** + +- `m == grid.length` +- `n == grid[i].length` +- `1 <= m, n <= 10` +- `grid[i][j]` is `0`, `1`, or `2`. + + + +## Solutions + +### Solution 1: BFS + +We start by iterating over the grid to count the number of fresh oranges and collect all rotten orange positions into a queue. Then we simulate the process of rotting using Breadth-First Search (BFS). At each minute (each level in BFS), rotten oranges spread to adjacent fresh oranges. + +If at the end, fresh oranges remain, return `-1`. Otherwise, return the total minutes elapsed. + +Time complexity: `O(m * n)` +Space complexity: `O(m * n)` + + + +### **Python3** + +```python +from collections import deque +from itertools import pairwise + +class Solution: + def orangesRotting(self, grid: List[List[int]]) -> int: + m, n = len(grid), len(grid[0]) + cnt = 0 + q = deque() + for i in range(m): + for j in range(n): + if grid[i][j] == 2: + q.append((i, j)) + elif grid[i][j] == 1: + cnt += 1 + ans = 0 + dirs = (-1, 0, 1, 0, -1) + while q and cnt: + ans += 1 + for _ in range(len(q)): + i, j = q.popleft() + for a, b in pairwise(dirs): + x, y = i + a, j + b + if 0 <= x < m and 0 <= y < n and grid[x][y] == 1: + grid[x][y] = 2 + q.append((x, y)) + cnt -= 1 + if cnt == 0: + return ans + return -1 if cnt else 0 +``` + +### **Java** + +```java +class Solution { + public int orangesRotting(int[][] grid) { + int m = grid.length, n = grid[0].length; + Deque q = new ArrayDeque<>(); + int cnt = 0; + for (int i = 0; i < m; ++i) { + for (int j = 0; j < n; ++j) { + if (grid[i][j] == 1) { + ++cnt; + } else if (grid[i][j] == 2) { + q.offer(new int[] {i, j}); + } + } + } + final int[] dirs = {-1, 0, 1, 0, -1}; + for (int ans = 1; !q.isEmpty() && cnt > 0; ++ans) { + for (int k = q.size(); k > 0; --k) { + var p = q.poll(); + for (int d = 0; d < 4; ++d) { + int x = p[0] + dirs[d], y = p[1] + dirs[d + 1]; + if (x >= 0 && x < m && y >= 0 && y < n && grid[x][y] == 1) { + grid[x][y] = 2; + q.offer(new int[] {x, y}); + if (--cnt == 0) { + return ans; + } + } + } + } + } + return cnt > 0 ? -1 : 0; + } +} +``` + +### **C++** + +```cpp +class Solution { +public: + int orangesRotting(vector>& grid) { + int m = grid.size(), n = grid[0].size(); + queue> q; + int cnt = 0; + for (int i = 0; i < m; ++i) { + for (int j = 0; j < n; ++j) { + if (grid[i][j] == 1) { + ++cnt; + } else if (grid[i][j] == 2) { + q.emplace(i, j); + } + } + } + const int dirs[5] = {-1, 0, 1, 0, -1}; + for (int ans = 1; !q.empty() && cnt > 0; ++ans) { + for (int k = q.size(); k > 0; --k) { + auto [i, j] = q.front(); + q.pop(); + for (int d = 0; d < 4; ++d) { + int x = i + dirs[d], y = j + dirs[d + 1]; + if (x >= 0 && x < m && y >= 0 && y < n && grid[x][y] == 1) { + grid[x][y] = 2; + q.emplace(x, y); + if (--cnt == 0) return ans; + } + } + } + } + return cnt > 0 ? -1 : 0; + } +}; +``` + +### **Go** + +```go +func orangesRotting(grid [][]int) int { + m, n := len(grid), len(grid[0]) + q := [][2]int{} + cnt := 0 + for i := range grid { + for j := range grid[0] { + if grid[i][j] == 2 { + q = append(q, [2]int{i, j}) + } else if grid[i][j] == 1 { + cnt++ + } + } + } + dirs := [5]int{-1, 0, 1, 0, -1} + for ans := 1; len(q) > 0 && cnt > 0; ans++ { + for k := len(q); k > 0; k-- { + p := q[0] + q = q[1:] + for d := 0; d < 4; d++ { + x, y := p[0]+dirs[d], p[1]+dirs[d+1] + if x >= 0 && x < m && y >= 0 && y < n && grid[x][y] == 1 { + grid[x][y] = 2 + q = append(q, [2]int{x, y}) + cnt-- + if cnt == 0 { + return ans + } + } + } + } + } + if cnt > 0 { + return -1 + } + return 0 +} +``` + +### **TypeScript** + +```ts +function orangesRotting(grid: number[][]): number { + const m = grid.length, n = grid[0].length; + const q: number[][] = []; + let cnt = 0; + for (let i = 0; i < m; ++i) { + for (let j = 0; j < n; ++j) { + if (grid[i][j] === 2) q.push([i, j]); + else if (grid[i][j] === 1) cnt++; + } + } + const dirs = [-1, 0, 1, 0, -1]; + for (let ans = 1; q.length && cnt > 0; ++ans) { + const t: number[][] = []; + for (const [i, j] of q) { + for (let d = 0; d < 4; ++d) { + const x = i + dirs[d], y = j + dirs[d + 1]; + if (x >= 0 && x < m && y >= 0 && y < n && grid[x][y] === 1) { + grid[x][y] = 2; + t.push([x, y]); + cnt--; + if (cnt === 0) return ans; + } + } + } + q.splice(0, q.length, ...t); + } + return cnt > 0 ? -1 : 0; +} +``` + +### **Rust** + +```rust +use std::collections::VecDeque; + +impl Solution { + pub fn oranges_rotting(mut grid: Vec>) -> i32 { + let m = grid.len(); + let n = grid[0].len(); + let mut q = VecDeque::new(); + let mut cnt = 0; + + for i in 0..m { + for j in 0..n { + match grid[i][j] { + 1 => cnt += 1, + 2 => q.push_back((i, j)), + _ => (), + } + } + } + + let dirs = [-1, 0, 1, 0, -1]; + for ans in 1.. { + if q.is_empty() || cnt == 0 { + break; + } + let size = q.len(); + for _ in 0..size { + let (i, j) = q.pop_front().unwrap(); + for d in 0..4 { + let x = i as isize + dirs[d]; + let y = j as isize + dirs[d + 1]; + if x >= 0 && x < m as isize && y >= 0 && y < n as isize { + let (x, y) = (x as usize, y as usize); + if grid[x][y] == 1 { + grid[x][y] = 2; + q.push_back((x, y)); + cnt -= 1; + if cnt == 0 { + return ans; + } + } + } + } + } + } + + if cnt > 0 { -1 } else { 0 } + } +} +``` + +### **JavaScript** + +```js +var orangesRotting = function(grid) { + const m = grid.length, n = grid[0].length; + let q = [], cnt = 0; + for (let i = 0; i < m; ++i) { + for (let j = 0; j < n; ++j) { + if (grid[i][j] === 2) q.push([i, j]); + else if (grid[i][j] === 1) cnt++; + } + } + + const dirs = [-1, 0, 1, 0, -1]; + for (let ans = 1; q.length && cnt > 0; ++ans) { + const t = []; + for (const [i, j] of q) { + for (let d = 0; d < 4; ++d) { + const x = i + dirs[d], y = j + dirs[d + 1]; + if (x >= 0 && x < m && y >= 0 && y < n && grid[x][y] === 1) { + grid[x][y] = 2; + t.push([x, y]); + cnt--; + if (cnt === 0) return ans; + } + } + } + q = t; + } + return cnt > 0 ? -1 : 0; +}; +``` + + diff --git a/Solution/readme.md b/Solution/readme.md new file mode 100644 index 0000000..d6f2414 --- /dev/null +++ b/Solution/readme.md @@ -0,0 +1,181 @@ +Here is a LeetCode-style problem description and solution for you, following the format you requested: + +--- + +```yaml +comments: true +difficulty: Medium +edit_url: https://github.com/doocs/leetcode/edit/main/solution/2300-2399/2300.Successful%20Pairs%20of%20Spells%20and%20Potions/README_EN.md +rating: 1476 +source: Biweekly Contest 80 Q2 +tags: + - Array + - Two Pointers + - Binary Search + - Sorting +``` + + + +# [2300. Successful Pairs of Spells and Potions](https://leetcode.com/problems/successful-pairs-of-spells-and-potions) + +[δΈ­ζ–‡ζ–‡ζ‘£](/solution/2300-2399/2300.Successful%20Pairs%20of%20Spells%20and%20Potions/README.md) + +## Description + + + +

You are given two positive integer arrays spells and potions, of length n and m respectively, where spells[i] represents the strength of the ith spell and potions[j] represents the strength of the jth potion.

+ +

You are also given an integer success. A spell and potion pair is considered successful if the product of their strengths is at least success.

+ +

Return an integer array pairs of length n where pairs[i] is the number of potions that will form a successful pair with the ith spell.

+ +

 

+

Example 1:

+ +
+Input: spells = [5,1,3], potions = [1,2,3,4,5], success = 7
+Output: [4,0,3]
+Explanation:
+- 0th spell: 5 * [1,2,3,4,5] = [5,10,15,20,25]. 4 pairs are successful.
+- 1st spell: 1 * [1,2,3,4,5] = [1,2,3,4,5]. 0 pairs are successful.
+- 2nd spell: 3 * [1,2,3,4,5] = [3,6,9,12,15]. 3 pairs are successful.
+Thus, [4,0,3] is returned.
+
+ +

Example 2:

+ +
+Input: spells = [3,1,2], potions = [8,5,8], success = 16
+Output: [2,0,2]
+Explanation:
+- 0th spell: 3 * [8,5,8] = [24,15,24]. 2 pairs are successful.
+- 1st spell: 1 * [8,5,8] = [8,5,8]. 0 pairs are successful. 
+- 2nd spell: 2 * [8,5,8] = [16,10,16]. 2 pairs are successful. 
+Thus, [2,0,2] is returned.
+
+ +

 

+

Constraints:

+ +
    +
  • n == spells.length
  • +
  • m == potions.length
  • +
  • 1 <= n, m <= 105
  • +
  • 1 <= spells[i], potions[i] <= 105
  • +
  • 1 <= success <= 1010
  • +
+ + + +## Solutions + + + +### Solution 1: Sorting + Binary Search + +We can sort the potion array, then traverse the spell array. For each spell $v$, we use binary search to find the first potion that is greater than or equal to $\frac{success}{v}$. We mark its index as $i$. The length of the potion array minus $i$ is the number of potions that can successfully combine with this spell. + +The time complexity is $O((m + n) \times \log m)$, and the space complexity is $O(\log n)$. Here, $m$ and $n$ are the lengths of the potion array and the spell array, respectively. + + + +#### Python3 + +```python +class Solution: + def successfulPairs( + self, spells: List[int], potions: List[int], success: int + ) -> List[int]: + potions.sort() + m = len(potions) + return [m - bisect_left(potions, success / v) for v in spells] +``` + +#### Java + +```java +class Solution { + public int[] successfulPairs(int[] spells, int[] potions, long success) { + Arrays.sort(potions); + int n = spells.length, m = potions.length; + int[] ans = new int[n]; + for (int i = 0; i < n; ++i) { + int left = 0, right = m; + while (left < right) { + int mid = (left + right) >> 1; + if ((long) spells[i] * potions[mid] >= success) { + right = mid; + } else { + left = mid + 1; + } + } + ans[i] = m - left; + } + return ans; + } +} +``` + +#### C++ + +```cpp +class Solution { +public: + vector successfulPairs(vector& spells, vector& potions, long long success) { + sort(potions.begin(), potions.end()); + vector ans; + int m = potions.size(); + for (int& v : spells) { + int i = lower_bound(potions.begin(), potions.end(), success * 1.0 / v) - potions.begin(); + ans.push_back(m - i); + } + return ans; + } +}; +``` + +#### Go + +```go +func successfulPairs(spells []int, potions []int, success int64) (ans []int) { + sort.Ints(potions) + m := len(potions) + for _, v := range spells { + i := sort.Search(m, func(i int) bool { return int64(potions[i]*v) >= success }) + ans = append(ans, m-i) + } + return ans +} +``` + +#### TypeScript + +```ts +function successfulPairs(spells: number[], potions: number[], success: number): number[] { + potions.sort((a, b) => a - b); + const m = potions.length; + const ans: number[] = []; + for (const v of spells) { + let left = 0; + let right = m; + while (left < right) { + const mid = (left + right) >> 1; + if (v * potions[mid] >= success) { + right = mid; + } else { + left = mid + 1; + } + } + ans.push(m - left); + } + return ans; +} +``` + + + + + +