Merge branch 'master' of github.com:youngyangyang04/leetcode-master

This commit is contained in:
programmercarl
2022-11-04 12:05:39 +08:00
25 changed files with 528 additions and 97 deletions

View File

@ -68,7 +68,7 @@
我在题目讲解中统一使用C++但你会发现下面几乎每篇题解都配有其他语言版本Java、Python、Go、JavaScript等等正是这些[热心小伙们](https://github.com/youngyangyang04/leetcode-master/graphs/contributors)的贡献的代码,当然我也会严格把控代码质量。
**所以也欢迎大家参与进来,完善题解的各个语言版本,拥抱开源,让更多小伙伴们益**
**所以也欢迎大家参与进来,完善题解的各个语言版本,拥抱开源,让更多小伙伴们益**
准备好了么刷题攻略开始咯go go go

View File

@ -152,25 +152,11 @@ class Solution:
def twoSum(self, nums: List[int], target: int) -> List[int]:
records = dict()
# 用枚举更方便,就不需要通过索引再去取当前位置的值
for idx, val in enumerate(nums):
if target - val not in records:
records[val] = idx
else:
return [records[target - val], idx] # 如果存在就返回字典记录索引和当前索引
```
Python (v2):
```python
class Solution:
def twoSum(self, nums: List[int], target: int) -> List[int]:
rec = {}
for i in range(len(nums)):
rest = target - nums[i]
# Use get to get the index of the data, making use of one of the dictionary properties.
if rec.get(rest, None) is not None: return [rec[rest], i]
rec[nums[i]] = i
for index, value in enumerate(nums):
if target - value in records:
return [records[target- value], index]
records[value] = index
return []
```
Go

View File

@ -655,7 +655,7 @@ impl Solution {
```Rust
// 双指针法
use std::collections::HashSet;
use std::cmp::Ordering;
impl Solution {
pub fn three_sum(nums: Vec<i32>) -> Vec<Vec<i32>> {
let mut result: Vec<Vec<i32>> = Vec::new();
@ -667,22 +667,21 @@ impl Solution {
if i > 0 && nums[i] == nums[i - 1] { continue; }
let (mut left, mut right) = (i + 1, len - 1);
while left < right {
if nums[i] + nums[left] + nums[right] > 0 {
right -= 1;
// 去重
while left < right && nums[right] == nums[right + 1] { right -= 1; }
} else if nums[i] + nums[left] + nums[right] < 0 {
left += 1;
// 去重
while left < right && nums[left] == nums[left - 1] { left += 1; }
} else {
result.push(vec![nums[i], nums[left], nums[right]]);
// 去重
right -= 1;
left += 1;
while left < right && nums[right] == nums[right + 1] { right -= 1; }
while left < right && nums[left] == nums[left - 1] { left += 1; }
}
match (nums[i] + nums[left] + nums[right]).cmp(&0){
Ordering::Equal =>{
result.push(vec![nums[i], nums[left], nums[right]]);
left +=1;
right -=1;
while left < right && nums[left] == nums[left - 1]{
left += 1;
}
while left < right && nums[right] == nums[right+1]{
right -= 1;
}
}
Ordering::Greater => right -= 1,
Ordering::Less => left += 1,
}
}
}
result

View File

@ -527,6 +527,7 @@ public class Solution
Rust:
```Rust
use std::cmp::Ordering;
impl Solution {
pub fn four_sum(nums: Vec<i32>, target: i32) -> Vec<Vec<i32>> {
let mut result: Vec<Vec<i32>> = Vec::new();
@ -545,22 +546,25 @@ impl Solution {
if i > k + 1 && nums[i] == nums[i - 1] { continue; }
let (mut left, mut right) = (i + 1, len - 1);
while left < right {
if nums[k] + nums[i] > target - (nums[left] + nums[right]) {
right -= 1;
// 去重
while left < right && nums[right] == nums[right + 1] { right -= 1; }
} else if nums[k] + nums[i] < target - (nums[left] + nums[right]) {
left += 1;
// 去重
while left < right && nums[left] == nums[left - 1] { left += 1; }
} else {
result.push(vec![nums[k], nums[i], nums[left], nums[right]]);
// 去重
while left < right && nums[right] == nums[right - 1] { right -= 1; }
while left < right && nums[left] == nums[left + 1] { left += 1; }
left += 1;
right -= 1;
}
match (nums[k] + nums[i] + nums[left] + nums[right]).cmp(&target){
Ordering::Equal => {
result.push(vec![nums[k], nums[i], nums[left], nums[right]]);
left += 1;
right -= 1;
while left < right && nums[left] == nums[left - 1]{
left += 1;
}
while left < right && nums[right] == nums[right + 1]{
right -= 1;
}
}
Ordering::Less => {
left +=1;
},
Ordering::Greater => {
right -= 1;
}
}
}
}
}

View File

@ -364,6 +364,40 @@ impl Solution {
dummy_head.next
}
}
```
C语言
```c
/**c语言单链表的定义
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode* removeNthFromEnd(struct ListNode* head, int n) {
//定义虚拟头节点dummy 并初始化使其指向head
struct ListNode* dummy = malloc(sizeof(struct ListNode));
dummy->val = 0;
dummy->next = head;
//定义 fast slow 双指针
struct ListNode* fast = head;
struct ListNode* slow = dummy;
for (int i = 0; i < n; ++i) {
fast = fast->next;
}
while (fast) {
fast = fast->next;
slow = slow->next;
}
slow->next = slow->next->next;//删除倒数第n个节点
head = dummy->next;
free(dummy);//删除虚拟节点dummy
return head;
}
```
<p align="center">

View File

@ -1299,6 +1299,53 @@ impl Solution {
}
```
> 前缀表统一减一
```rust
impl Solution {
pub fn get_next(next_len: usize, s: &Vec<char>) -> Vec<i32> {
let mut next = vec![-1; next_len];
let mut j = -1;
for i in 1..s.len() {
while j >= 0 && s[(j + 1) as usize] != s[i] {
j = next[j as usize];
}
if s[i] == s[(j + 1) as usize] {
j += 1;
}
next[i] = j;
}
next
}
pub fn str_str(haystack: String, needle: String) -> i32 {
if needle.is_empty() {
return 0;
}
if haystack.len() < needle.len() {
return -1;
}
let (haystack_chars, needle_chars) = (
haystack.chars().collect::<Vec<char>>(),
needle.chars().collect::<Vec<char>>(),
);
let mut j = -1;
let next = Self::get_next(needle.len(), &needle_chars);
for (i, v) in haystack_chars.into_iter().enumerate() {
while j >= 0 && v != needle_chars[(j + 1) as usize] {
j = next[j as usize];
}
if v == needle_chars[(j + 1) as usize] {
j += 1;
}
if j == needle_chars.len() as i32 - 1 {
return (i - needle_chars.len() + 1) as i32;
}
}
-1
}
}
```
<p align="center">
<a href="https://programmercarl.com/other/kstar.html" target="_blank">
<img src="../pics/网站星球宣传海报.jpg" width="1000"/>

View File

@ -256,7 +256,54 @@ int totalNQueens(int n){
return answer;
}
```
Java
```java
class Solution {
int count = 0;
public int totalNQueens(int n) {
char[][] board = new char[n][n];
for (char[] chars : board) {
Arrays.fill(chars, '.');
}
backTrack(n, 0, board);
return count;
}
private void backTrack(int n, int row, char[][] board) {
if (row == n) {
count++;
return;
}
for (int col = 0; col < n; col++) {
if (isValid(row, col, n, board)) {
board[row][col] = 'Q';
backTrack(n, row + 1, board);
board[row][col] = '.';
}
}
}
private boolean isValid(int row, int col, int n, char[][] board) {
// 检查列
for (int i = 0; i < row; ++i) {
if (board[i][col] == 'Q') {
return false;
}
}
// 检查45度对角线
for (int i = row - 1, j = col - 1; i >= 0 && j >= 0; i--, j--) {
if (board[i][j] == 'Q') {
return false;
}
}
// 检查135度对角线
for (int i = row - 1, j = col + 1; i >= 0 && j <= n - 1; i--, j++) {
if (board[i][j] == 'Q') {
return false;
}
}
return true;
}
}
```
<p align="center">
<a href="https://programmercarl.com/other/kstar.html" target="_blank">
<img src="../pics/网站星球宣传海报.jpg" width="1000"/>

View File

@ -409,7 +409,44 @@ class Solution:
```
*****
Go:
> 单调栈
```go
func largestRectangleArea(heights []int) int {
// 声明max并初始化为0
max := 0
// 使用切片实现栈
stack := make([]int, 0)
// 数组头部加入0
heights = append([]int{0}, heights...)
// 数组尾部加入0
heights = append(heights, 0)
// 初始化栈序号从0开始
stack = append(stack, 0)
for i := 1; i < len(heights); i++ {
// 结束循环条件为:当即将入栈元素>top元素也就是形成非单调递增的趋势
for heights[stack[len(stack)-1]] > heights[i] {
// mid 是top
mid := stack[len(stack)-1]
// 出栈
stack = stack[0 : len(stack)-1]
// left是top的下一位元素i是将要入栈的元素
left := stack[len(stack)-1]
// 高度x宽度
tmp := heights[mid] * (i - left - 1)
if tmp > max {
max = tmp
}
}
stack = append(stack, i)
}
return max
}
```
JavaScript:
```javascript

View File

@ -262,6 +262,8 @@ class Solution:
```
### Python3
不使用used数组
```python3
class Solution:
def subsetsWithDup(self, nums: List[int]) -> List[List[int]]:
@ -288,6 +290,28 @@ class Solution:
return res
```
使用used数组
```python3
class Solution:
def subsetsWithDup(self, nums: List[int]) -> List[List[int]]:
result = []
path = []
nums.sort()
used = [0] * len(nums)
def backtrack(nums, startIdx):
result.append(path[:])
for i in range(startIdx, len(nums)):
if i > startIdx and nums[i] == nums[i-1] and used[i-1] == 0:
continue
used[i] = 1
path.append(nums[i])
backtrack(nums, i+1)
path.pop()
used[i] = 0
backtrack(nums, 0)
return result
```
### Go
```Go
@ -526,7 +550,7 @@ func subsetsWithDup(_ nums: [Int]) -> [[Int]] {
### Scala
不使用userd数组:
不使用used数组:
```scala
object Solution {

View File

@ -464,6 +464,47 @@ function maxProfit(prices: number[]): number {
};
```
C#
> 贪心法
```csharp
public class Solution
{
public int MaxProfit(int[] prices)
{
int min = Int32.MaxValue;
int res = 0;
for (int i = 0; i < prices.Length; i++)
{
min = Math.Min(prices[i], min);
res = Math.Max(prices[i] - min, res);
}
return res;
}
}
```
> 动态规划
```csharp
public class Solution
{
public int MaxProfit(int[] prices)
{
int[] dp = new int[2];
int size = prices.Length;
(dp[0], dp[1]) = (-prices[0], 0);
for (int i = 0; i < size; i++)
{
dp[0] = Math.Max(dp[0], -prices[i]);
dp[1] = Math.Max(dp[1], dp[0]+prices[i]);
}
return dp[1];
}
}
```
@ -471,3 +512,4 @@ function maxProfit(prices: number[]): number {
<a href="https://programmercarl.com/other/kstar.html" target="_blank">
<img src="../pics/网站星球宣传海报.jpg" width="1000"/>
</a>

View File

@ -169,8 +169,6 @@ class Solution {
}
```
Python
> 版本一:
@ -253,8 +251,6 @@ func max(a,b int)int{
}
```
Javascript
```javascript
// 方法一动态规划dp 数组)
@ -331,9 +327,47 @@ function maxProfit(prices: number[]): number {
};
```
C#
> 贪心法
```csharp
public class Solution
{
public int MaxProfit(int[] prices)
{
int res = 0;
for (int i = 1; i < prices.Length; i++)
res += Math.Max(0, prices[i] - prices[i-1]);
return res;
}
}
```
> 动态规划
```csharp
public class Solution
{
public int MaxProfit(int[] prices)
{
int[] dp = new int[2];
dp[0] = -prices[0];
for (int i = 1; i < prices.Length; i++)
{
dp[0] = dp[0]>dp[1] - prices[i]?dp[0]:dp[1] - prices[i];
dp[1] = dp[1] > dp[0] + prices[i] ? dp[1] : dp[0] + prices[i];
}
return dp[1];
}
}
```
<p align="center">
<a href="https://programmercarl.com/other/kstar.html" target="_blank">
<img src="../pics/网站星球宣传海报.jpg" width="1000"/>
</a>

View File

@ -31,7 +31,7 @@
# 思路
以示例1为例从这个图中可以看出 hit 到 cog的路线不止一条有三条条是最短的长度为5条长度为6。
以示例1为例从这个图中可以看出 hit 到 cog的路线不止一条有三条条是最短的长度为5条长度为6。
![](https://code-thinking-1253855093.file.myqcloud.com/pics/20210827175432.png)

View File

@ -416,24 +416,31 @@ func backTree(n,k,startIndex int,track *[]int,result *[][]int){
* @return {number[][]}
*/
var combinationSum3 = function(k, n) {
const backtrack = (start) => {
const l = path.length;
if (l === k) {
const sum = path.reduce((a, b) => a + b);
if (sum === n) {
res.push([...path]);
}
return;
let res = [];
let path = [];
let sum = 0;
const dfs = (path,index) => {
// 剪枝操作
if (sum > n){
return
}
for (let i = start; i <= 9 - (k - l) + 1; i++) {
if (path.length == k) {
if(sum == n){
res.push([...path]);
return
}
}
for (let i = index; i <= 9 - (k-path.length) + 1;i++) {
path.push(i);
backtrack(i + 1);
path.pop();
sum = sum + i;
index += 1;
dfs(path,index);
sum -= i
path.pop()
}
}
let res = [], path = [];
backtrack(1);
return res;
dfs(path,1);
return res
};
```

View File

@ -328,13 +328,11 @@ var lowestCommonAncestor = function(root, p, q) {
}
if(root.val>p.val&&root.val>q.val) {
// 向左子树查询
let left = lowestCommonAncestor(root.left,p,q);
return left !== null&&left;
return root.left = lowestCommonAncestor(root.left,p,q);
}
if(root.val<p.val&&root.val<q.val) {
// 向右子树查询
let right = lowestCommonAncestor(root.right,p,q);
return right !== null&&right;
return root.right = lowestCommonAncestor(root.right,p,q);
}
return root;
};

View File

@ -88,7 +88,7 @@ public:
对于窗口里的元素{2, 3, 5, 1 ,4},单调队列里只维护{5, 4} 就够了,保持单调队列里单调递减,此时队列出口元素就是窗口里最大元素。
此时大家应该怀疑单调队列里维护着{5, 4} 怎么配合窗口行滑动呢?
此时大家应该怀疑单调队列里维护着{5, 4} 怎么配合窗口行滑动呢?
设计单调队列的时候pop和push操作要保持如下规则
@ -297,15 +297,18 @@ class Solution {
Python
```python
from collections import deque
class MyQueue: #单调队列(从大到小
def __init__(self):
self.queue = [] #使用list来实现单调队列
self.queue = deque() #这里需要使用deque实现单调队列直接使用list会超时
#每次弹出的时候,比较当前要弹出的数值是否等于队列出口元素的数值,如果相等则弹出。
#同时pop之前判断队列当前是否为空。
def pop(self, value):
if self.queue and value == self.queue[0]:
self.queue.pop(0)#list.pop()时间复杂度为O(n),这里可以使用collections.deque()
self.queue.popleft()#list.pop()时间复杂度为O(n),这里需要使用collections.deque()
#如果push的数值大于入口元素的数值那么就将队列后端的数值弹出直到push的数值小于等于队列入口元素的数值为止。
#这样就保持了队列里的数值是单调从大到小的了。

View File

@ -355,16 +355,18 @@ class Solution:
tickets_dict = defaultdict(list)
for item in tickets:
tickets_dict[item[0]].append(item[1])
# 给每一个机场的到达机场排序小的在前面在回溯里首先被pop(0出去
# 这样最先找的的path就是排序最小的答案直接返回
for airport in tickets_dict: tickets_dict[airport].sort()
'''
tickets_dict里面的内容是这样的
{'JFK': ['SFO', 'ATL'], 'SFO': ['ATL'], 'ATL': ['JFK', 'SFO']})
{'JFK': ['ATL', 'SFO'], 'SFO': ['ATL'], 'ATL': ['JFK', 'SFO']})
'''
path = ["JFK"]
def backtracking(start_point):
# 终止条件
if len(path) == len(tickets) + 1:
return True
tickets_dict[start_point].sort()
for _ in tickets_dict[start_point]:
#必须及时删除,避免出现死循环
end_point = tickets_dict[start_point].pop(0)

View File

@ -91,7 +91,7 @@ public:
对应C++代码如下:
```c++
```CPP
class Solution {
public:
vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
@ -310,6 +310,22 @@ impl Solution {
}
```
解法2:
```rust
use std::collections::HashSet;
impl Solution {
pub fn intersection(nums1: Vec<i32>, nums2: Vec<i32>) -> Vec<i32> {
nums1
.into_iter()
.collect::<HashSet<_>>()
.intersection(&nums2.into_iter().collect::<HashSet<_>>())
.copied()
.collect()
}
}
```
C:
```C
int* intersection1(int* nums1, int nums1Size, int* nums2, int nums2Size, int* returnSize){

View File

@ -344,6 +344,48 @@ class Solution:
return root
```
**迭代法**
```python
class Solution:
def deleteNode(self, root: Optional[TreeNode], key: int) -> Optional[TreeNode]:
# 找到节点后分两步1. 把节点的左子树和右子树连起来2. 把右子树跟父节点连起来
# root is None
if not root: return root
p = root
last = None
while p:
if p.val==key:
# 1. connect left to right
# right is not None -> left is None | left is not None
if p.right:
if p.left:
node = p.right
while node.left:
node = node.left
node.left = p.left
right = p.right
else:
# right is None -> right=left
right = p.left
# 2. connect right to last
if last==None:
root = right
elif last.val>key:
last.left = right
else:
last.right = right
# 3. return
break
else:
# Update last and continue
last = p
if p.val>key:
p = p.left
else:
p = p.right
return root
```
## Go
```Go
// 递归版本

View File

@ -615,6 +615,37 @@ impl Solution {
}
```
>前缀表统一减一
```rust
impl Solution {
pub fn get_next(next_len: usize, s: &Vec<char>) -> Vec<i32> {
let mut next = vec![-1; next_len];
let mut j = -1;
for i in 1..s.len() {
while j >= 0 && s[i] != s[(j + 1) as usize] {
j = next[j as usize];
}
if s[i] == s[(j + 1) as usize] {
j += 1;
}
next[i] = j;
}
next
}
pub fn repeated_substring_pattern(s: String) -> bool {
let s_chars = s.chars().collect::<Vec<char>>();
let next = Self::get_next(s_chars.len(), &s_chars);
if next[s_chars.len() - 1] >= 0
&& s_chars.len() % (s_chars.len() - (next[s_chars.len() - 1] + 1) as usize) == 0
{
return true;
}
false
}
}
```
<p align="center">
<a href="https://programmercarl.com/other/kstar.html" target="_blank">

View File

@ -7,7 +7,7 @@
## 518. 零钱兑换 II
[力扣题目链接](https://leetcode.cn/problems/coin-change-2/)
[力扣题目链接](https://leetcode.cn/problems/coin-change-ii/)
难度:中等

View File

@ -399,19 +399,42 @@ object Solution {
}
}
```
版本二: 首先利用sliding每隔k个进行分割随后转换为数组,再使用zipWithIndex添加每个数组的索引紧接着利用map做变换如果索引%2==0则说明需要翻转否则原封不动最后再转换为String
版本二: 首先利用grouped每隔k个进行分割再使用zipWithIndex添加每个数组的索引紧接着利用map做变换如果索引%2==0则说明需要翻转否则原封不动最后再转换为String
```scala
object Solution {
def reverseStr(s: String, k: Int): String = {
s.sliding(k, k)
.toArray
.zipWithIndex
.map(v => if (v._2 % 2 == 0) v._1.reverse else v._1)
// s = "abcdefg", k = 2
s.grouped(k) // Iterator ["ab", "cd", "ef", "g"]
.zipWithIndex // Iterator [("ab", 0), ("cd", 1), ("ef", 2), ("g", 3)]
.map {
case (subStr, index) =>
if (index % 2 == 0) subStr.reverse else subStr
}
.mkString
}
}
```
版本三: (递归)
```scala
import scala.annotation.tailrec
object Solution {
def reverseStr(s: String, k: Int): String = {
@tailrec // 这个函数已经优化成了尾递归
def reverse(s: String, needToReverse: Boolean, history: String): String = {
// 截取前k个字符判断是否翻转
val subStr = if (needToReverse) s.take(k).reverse else s.take(k)
// 如果字符串长度小于k返回结果
// 否则,对于剩余字符串进行同样的操作
if (s.length < k) history + subStr
else reverse(s.drop(k), !needToReverse, history + subStr)
}
reverse(s, true, "")
}
}
```
Rust:
```Rust

View File

@ -330,6 +330,26 @@ class Solution:
return root
```
**递归法** - 无返回值 有注释 不用Helper function
```python
class Solution:
def insertIntoBST(self, root: Optional[TreeNode], val: int) -> Optional[TreeNode]:
if not root: # for root==None
return TreeNode(val)
if root.val<val:
if root.right==None: # find the parent
root.right = TreeNode(val)
else: # not found, keep searching
self.insertIntoBST(root.right, val)
if root.val>val:
if root.left==None: # found the parent
root.left = TreeNode(val)
else: # not found, keep searching
self.insertIntoBST(root.left, val)
# return the final tree
return root
```
**迭代法**
与无返回值的递归函数的思路大体一致
```python
@ -337,16 +357,15 @@ class Solution:
def insertIntoBST(self, root: TreeNode, val: int) -> TreeNode:
if not root:
return TreeNode(val)
parent = None
parent = None # 此步可以省略
cur = root
# 用while循环不断地找新节点的parent
while cur:
parent = cur # 首先保存当前非空节点作为下一次迭代的父节点
if cur.val < val:
parent = cur
cur = cur.right
elif cur.val > val:
parent = cur
cur = cur.left
# 运行到这意味着已经跳出上面的while循环,

View File

@ -451,6 +451,42 @@ object Solution {
}
}
```
Rust:
```rust
impl Solution {
pub fn common_chars(words: Vec<String>) -> Vec<String> {
if words.is_empty() {
return vec![];
}
let mut res = vec![];
let mut hash = vec![0; 26];
for i in words[0].bytes() {
hash[(i - b'a') as usize] += 1;
}
for i in words.iter().skip(1) {
let mut other_hash_str = vec![0; 26];
for j in i.bytes() {
other_hash_str[(j - b'a') as usize] += 1;
}
for k in 0..26 {
hash[k] = hash[k].min(other_hash_str[k]);
}
}
for (i, v) in hash.iter_mut().enumerate() {
while *v > 0 {
res.push(((i as u8 + b'a') as char).to_string());
*v -= 1;
}
}
res
}
}
```
<p align="center">
<a href="https://programmercarl.com/other/kstar.html" target="_blank">
<img src="../pics/网站星球宣传海报.jpg" width="1000"/>

View File

@ -117,7 +117,7 @@ class Solution:
diff -= 1
else:
diff += 1
if tilt == 0:
if diff == 0:
ans += 1
return ans
```

View File

@ -59,7 +59,7 @@ C++标准库是有多个版本的要知道我们使用的STL是哪个版本
![栈与队列理论3](https://img-blog.csdnimg.cn/20210104235459376.png)
**我们常用的SGI STL如果没有指定底层实现的话默认是以deque为缺省情况下栈的层结构。**
**我们常用的SGI STL如果没有指定底层实现的话默认是以deque为缺省情况下栈的层结构。**
deque是一个双向队列只要封住一段只开通另一端就可以实现栈的逻辑了。