mirror of
https://github.com/youngyangyang04/leetcode-master.git
synced 2025-07-14 23:11:37 +08:00
Merge branch 'master' of github.com:youngyangyang04/leetcode-master
This commit is contained in:
@ -134,12 +134,13 @@ public int[] twoSum(int[] nums, int target) {
|
||||
}
|
||||
Map<Integer, Integer> map = new HashMap<>();
|
||||
for(int i = 0; i < nums.length; i++){
|
||||
int temp = target - nums[i];
|
||||
int temp = target - nums[i]; // 遍历当前元素,并在map中寻找是否有匹配的key
|
||||
if(map.containsKey(temp)){
|
||||
res[1] = i;
|
||||
res[0] = map.get(temp);
|
||||
break;
|
||||
}
|
||||
map.put(nums[i], i);
|
||||
map.put(nums[i], i); // 如果没找到匹配对,就把访问过的元素和下标加入到map中
|
||||
}
|
||||
return res;
|
||||
}
|
||||
@ -152,16 +153,17 @@ class Solution:
|
||||
def twoSum(self, nums: List[int], target: int) -> List[int]:
|
||||
records = dict()
|
||||
|
||||
for index, value in enumerate(nums):
|
||||
if target - value in records:
|
||||
for index, value in enumerate(nums):
|
||||
if target - value in records: # 遍历当前元素,并在map中寻找是否有匹配的key
|
||||
return [records[target- value], index]
|
||||
records[value] = index
|
||||
records[value] = index # 遍历当前元素,并在map中寻找是否有匹配的key
|
||||
return []
|
||||
```
|
||||
|
||||
Go:
|
||||
|
||||
```go
|
||||
// 暴力解法
|
||||
func twoSum(nums []int, target int) []int {
|
||||
for k1, _ := range nums {
|
||||
for k2 := k1 + 1; k2 < len(nums); k2++ {
|
||||
@ -216,11 +218,11 @@ Javascript
|
||||
```javascript
|
||||
var twoSum = function (nums, target) {
|
||||
let hash = {};
|
||||
for (let i = 0; i < nums.length; i++) {
|
||||
for (let i = 0; i < nums.length; i++) { // 遍历当前元素,并在map中寻找是否有匹配的key
|
||||
if (hash[target - nums[i]] !== undefined) {
|
||||
return [i, hash[target - nums[i]]];
|
||||
}
|
||||
hash[nums[i]] = i;
|
||||
hash[nums[i]] = i; // 如果没找到匹配对,就把访问过的元素和下标加入到map中
|
||||
}
|
||||
return [];
|
||||
};
|
||||
|
@ -253,13 +253,15 @@ class Solution {
|
||||
public List<List<Integer>> threeSum(int[] nums) {
|
||||
List<List<Integer>> result = new ArrayList<>();
|
||||
Arrays.sort(nums);
|
||||
|
||||
// 找出a + b + c = 0
|
||||
// a = nums[i], b = nums[left], c = nums[right]
|
||||
for (int i = 0; i < nums.length; i++) {
|
||||
if (nums[i] > 0) {
|
||||
// 排序之后如果第一个元素已经大于零,那么无论如何组合都不可能凑成三元组,直接返回结果就可以了
|
||||
if (nums[i] > 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
if (i > 0 && nums[i] == nums[i - 1]) {
|
||||
if (i > 0 && nums[i] == nums[i - 1]) { // 去重a
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -273,7 +275,7 @@ class Solution {
|
||||
left++;
|
||||
} else {
|
||||
result.add(Arrays.asList(nums[i], nums[left], nums[right]));
|
||||
|
||||
// 去重逻辑应该放在找到一个三元组之后,对b 和 c去重
|
||||
while (right > left && nums[right] == nums[right - 1]) right--;
|
||||
while (right > left && nums[left] == nums[left + 1]) left++;
|
||||
|
||||
@ -294,12 +296,15 @@ class Solution:
|
||||
ans = []
|
||||
n = len(nums)
|
||||
nums.sort()
|
||||
# 找出a + b + c = 0
|
||||
# a = nums[i], b = nums[left], c = nums[right]
|
||||
for i in range(n):
|
||||
left = i + 1
|
||||
right = n - 1
|
||||
if nums[i] > 0:
|
||||
# 排序之后如果第一个元素已经大于零,那么无论如何组合都不可能凑成三元组,直接返回结果就可以了
|
||||
if nums[i] > 0:
|
||||
break
|
||||
if i >= 1 and nums[i] == nums[i - 1]:
|
||||
if i >= 1 and nums[i] == nums[i - 1]: # 去重a
|
||||
continue
|
||||
while left < right:
|
||||
total = nums[i] + nums[left] + nums[right]
|
||||
@ -309,13 +314,14 @@ class Solution:
|
||||
left += 1
|
||||
else:
|
||||
ans.append([nums[i], nums[left], nums[right]])
|
||||
# 去重逻辑应该放在找到一个三元组之后,对b 和 c去重
|
||||
while left != right and nums[left] == nums[left + 1]: left += 1
|
||||
while left != right and nums[right] == nums[right - 1]: right -= 1
|
||||
left += 1
|
||||
right -= 1
|
||||
return ans
|
||||
```
|
||||
Python (v2):
|
||||
Python (v3):
|
||||
|
||||
```python
|
||||
class Solution:
|
||||
@ -344,32 +350,36 @@ class Solution:
|
||||
Go:
|
||||
|
||||
```Go
|
||||
func threeSum(nums []int)[][]int{
|
||||
func threeSum(nums []int) [][]int {
|
||||
sort.Ints(nums)
|
||||
res:=[][]int{}
|
||||
|
||||
for i:=0;i<len(nums)-2;i++{
|
||||
n1:=nums[i]
|
||||
if n1>0{
|
||||
res := [][]int{}
|
||||
// 找出a + b + c = 0
|
||||
// a = nums[i], b = nums[left], c = nums[right]
|
||||
for i := 0; i < len(nums)-2; i++ {
|
||||
// 排序之后如果第一个元素已经大于零,那么无论如何组合都不可能凑成三元组,直接返回结果就可以了
|
||||
n1 := nums[i]
|
||||
if n1 > 0 {
|
||||
break
|
||||
}
|
||||
if i>0&&n1==nums[i-1]{
|
||||
// 去重a
|
||||
if i > 0 && n1 == nums[i-1] {
|
||||
continue
|
||||
}
|
||||
l,r:=i+1,len(nums)-1
|
||||
for l<r{
|
||||
n2,n3:=nums[l],nums[r]
|
||||
if n1+n2+n3==0{
|
||||
res=append(res,[]int{n1,n2,n3})
|
||||
for l<r&&nums[l]==n2{
|
||||
l, r := i+1, len(nums)-1
|
||||
for l < r {
|
||||
n2, n3 := nums[l], nums[r]
|
||||
if n1+n2+n3 == 0 {
|
||||
res = append(res, []int{n1, n2, n3})
|
||||
// 去重逻辑应该放在找到一个三元组之后,对b 和 c去重
|
||||
for l < r && nums[l] == n2 {
|
||||
l++
|
||||
}
|
||||
for l<r&&nums[r]==n3{
|
||||
for l < r && nums[r] == n3 {
|
||||
r--
|
||||
}
|
||||
}else if n1+n2+n3<0{
|
||||
} else if n1+n2+n3 < 0 {
|
||||
l++
|
||||
}else {
|
||||
} else {
|
||||
r--
|
||||
}
|
||||
}
|
||||
|
@ -136,25 +136,26 @@ class Solution {
|
||||
Arrays.sort(nums);
|
||||
|
||||
for (int i = 0; i < nums.length; i++) {
|
||||
|
||||
|
||||
// nums[i] > target 直接返回, 剪枝操作
|
||||
if (nums[i] > 0 && nums[i] > target) {
|
||||
return result;
|
||||
}
|
||||
|
||||
if (i > 0 && nums[i - 1] == nums[i]) {
|
||||
|
||||
if (i > 0 && nums[i - 1] == nums[i]) { // 对nums[i]去重
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int j = i + 1; j < nums.length; j++) {
|
||||
|
||||
if (j > i + 1 && nums[j - 1] == nums[j]) {
|
||||
if (j > i + 1 && nums[j - 1] == nums[j]) { // 对nums[j]去重
|
||||
continue;
|
||||
}
|
||||
|
||||
int left = j + 1;
|
||||
int right = nums.length - 1;
|
||||
while (right > left) {
|
||||
// nums[k] + nums[i] + nums[left] + nums[right] > target int会溢出
|
||||
long sum = (long) nums[i] + nums[j] + nums[left] + nums[right];
|
||||
if (sum > target) {
|
||||
right--;
|
||||
@ -162,7 +163,7 @@ class Solution {
|
||||
left++;
|
||||
} else {
|
||||
result.add(Arrays.asList(nums[i], nums[j], nums[left], nums[right]));
|
||||
|
||||
// 对nums[left]和nums[right]去重
|
||||
while (right > left && nums[right] == nums[right - 1]) right--;
|
||||
while (right > left && nums[left] == nums[left + 1]) left++;
|
||||
|
||||
@ -186,10 +187,10 @@ class Solution:
|
||||
nums.sort()
|
||||
n = len(nums)
|
||||
res = []
|
||||
for i in range(n):
|
||||
if i > 0 and nums[i] == nums[i - 1]: continue
|
||||
for i in range(n):
|
||||
if i > 0 and nums[i] == nums[i - 1]: continue # 对nums[i]去重
|
||||
for k in range(i+1, n):
|
||||
if k > i + 1 and nums[k] == nums[k-1]: continue
|
||||
if k > i + 1 and nums[k] == nums[k-1]: continue # 对nums[k]去重
|
||||
p = k + 1
|
||||
q = n - 1
|
||||
|
||||
@ -198,6 +199,7 @@ class Solution:
|
||||
elif nums[i] + nums[k] + nums[p] + nums[q] < target: p += 1
|
||||
else:
|
||||
res.append([nums[i], nums[k], nums[p], nums[q]])
|
||||
# 对nums[p]和nums[q]去重
|
||||
while p < q and nums[p] == nums[p + 1]: p += 1
|
||||
while p < q and nums[q] == nums[q - 1]: q -= 1
|
||||
p += 1
|
||||
@ -258,12 +260,12 @@ func fourSum(nums []int, target int) [][]int {
|
||||
// if n1 > target { // 不能这样写,因为可能是负数
|
||||
// break
|
||||
// }
|
||||
if i > 0 && n1 == nums[i-1] {
|
||||
if i > 0 && n1 == nums[i-1] { // 对nums[i]去重
|
||||
continue
|
||||
}
|
||||
for j := i + 1; j < len(nums)-2; j++ {
|
||||
n2 := nums[j]
|
||||
if j > i+1 && n2 == nums[j-1] {
|
||||
if j > i+1 && n2 == nums[j-1] { // 对nums[j]去重
|
||||
continue
|
||||
}
|
||||
l := j + 1
|
||||
@ -320,6 +322,8 @@ var fourSum = function(nums, target) {
|
||||
if(sum < target) { l++; continue}
|
||||
if(sum > target) { r--; continue}
|
||||
res.push([nums[i], nums[j], nums[l], nums[r]]);
|
||||
|
||||
// 对nums[left]和nums[right]去重
|
||||
while(l < r && nums[l] === nums[++l]);
|
||||
while(l < r && nums[r] === nums[--r]);
|
||||
}
|
||||
|
@ -493,6 +493,33 @@ object Solution {
|
||||
}
|
||||
```
|
||||
|
||||
rust:
|
||||
|
||||
```rust
|
||||
impl Solution {
|
||||
pub fn is_valid(s: String) -> bool {
|
||||
if s.len() % 2 == 1 {
|
||||
return false;
|
||||
}
|
||||
let mut stack = vec![];
|
||||
let mut chars: Vec<char> = s.chars().collect();
|
||||
while let Some(s) = chars.pop() {
|
||||
match s {
|
||||
')' => stack.push('('),
|
||||
']' => stack.push('['),
|
||||
'}' => stack.push('{'),
|
||||
_ => {
|
||||
if stack.is_empty() || stack.pop().unwrap() != s {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
stack.is_empty()
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
<p align="center">
|
||||
<a href="https://programmercarl.com/other/kstar.html" target="_blank">
|
||||
<img src="../pics/网站星球宣传海报.jpg" width="1000"/>
|
||||
|
@ -199,21 +199,15 @@ Python:
|
||||
```python3
|
||||
class Solution:
|
||||
def removeElement(self, nums: List[int], val: int) -> int:
|
||||
if nums is None or len(nums)==0:
|
||||
return 0
|
||||
l=0
|
||||
r=len(nums)-1
|
||||
while l<r:
|
||||
while(l<r and nums[l]!=val):
|
||||
l+=1
|
||||
while(l<r and nums[r]==val):
|
||||
r-=1
|
||||
nums[l], nums[r]=nums[r], nums[l]
|
||||
print(nums)
|
||||
if nums[l]==val:
|
||||
return l
|
||||
else:
|
||||
return l+1
|
||||
# 快指针遍历元素
|
||||
fast = 0
|
||||
# 慢指针记录位置
|
||||
slow = 0
|
||||
for fast in range(len(nums)):
|
||||
if nums[fast] != val:
|
||||
nums[slow] = nums[fast]
|
||||
slow += 1
|
||||
return slow
|
||||
```
|
||||
|
||||
|
||||
|
@ -94,7 +94,7 @@ next数组就是一个前缀表(prefix table)。
|
||||
|
||||
**前缀表是用来回退的,它记录了模式串与主串(文本串)不匹配的时候,模式串应该从哪里开始重新匹配。**
|
||||
|
||||
为了清楚的了解前缀表的来历,我们来举一个例子:
|
||||
为了清楚地了解前缀表的来历,我们来举一个例子:
|
||||
|
||||
要在文本串:aabaabaafa 中查找是否出现过一个模式串:aabaaf。
|
||||
|
||||
@ -110,9 +110,9 @@ next数组就是一个前缀表(prefix table)。
|
||||
|
||||

|
||||
|
||||
动画里,我特意把 子串`aa` 标记上了,这是有原因的,大家先注意一下,后面还会说道。
|
||||
动画里,我特意把 子串`aa` 标记上了,这是有原因的,大家先注意一下,后面还会说到。
|
||||
|
||||
可以看出,文本串中第六个字符b 和 模式串的第六个字符f,不匹配了。如果暴力匹配,会发现不匹配,此时就要从头匹配了。
|
||||
可以看出,文本串中第六个字符b 和 模式串的第六个字符f,不匹配了。如果暴力匹配,发现不匹配,此时就要从头匹配了。
|
||||
|
||||
但如果使用前缀表,就不会从头匹配,而是从上次已经匹配的内容开始匹配,找到了模式串中第三个字符b继续开始匹配。
|
||||
|
||||
@ -157,7 +157,7 @@ next数组就是一个前缀表(prefix table)。
|
||||
|
||||
以下这句话,对于理解为什么使用前缀表可以告诉我们匹配失败之后跳到哪里重新匹配 非常重要!
|
||||
|
||||
**下标5之前这部分的字符串(也就是字符串aabaa)的最长相等的前缀 和 后缀字符串是 子字符串aa ,因为找到了最长相等的前缀和后缀,匹配失败的位置是后缀子串的后面,那么我们找到与其相同的前缀的后面从新匹配就可以了。**
|
||||
**下标5之前这部分的字符串(也就是字符串aabaa)的最长相等的前缀 和 后缀字符串是 子字符串aa ,因为找到了最长相等的前缀和后缀,匹配失败的位置是后缀子串的后面,那么我们找到与其相同的前缀的后面重新匹配就可以了。**
|
||||
|
||||
所以前缀表具有告诉我们当前位置匹配失败,跳到之前已经匹配过的地方的能力。
|
||||
|
||||
@ -199,7 +199,7 @@ next数组就是一个前缀表(prefix table)。
|
||||
|
||||
所以要看前一位的 前缀表的数值。
|
||||
|
||||
前一个字符的前缀表的数值是2, 所有把下标移动到下标2的位置继续比配。 可以再反复看一下上面的动画。
|
||||
前一个字符的前缀表的数值是2, 所以把下标移动到下标2的位置继续比配。 可以再反复看一下上面的动画。
|
||||
|
||||
最后就在文本串中找到了和模式串匹配的子串了。
|
||||
|
||||
@ -211,7 +211,7 @@ next数组就可以是前缀表,但是很多实现都是把前缀表统一减
|
||||
|
||||
为什么这么做呢,其实也是很多文章视频没有解释清楚的地方。
|
||||
|
||||
其实**这并不涉及到KMP的原理,而是具体实现,next数组即可以就是前缀表,也可以是前缀表统一减一(右移一位,初始位置为-1)。**
|
||||
其实**这并不涉及到KMP的原理,而是具体实现,next数组既可以就是前缀表,也可以是前缀表统一减一(右移一位,初始位置为-1)。**
|
||||
|
||||
后面我会提供两种不同的实现代码,大家就明白了。
|
||||
|
||||
@ -231,7 +231,7 @@ next数组就可以是前缀表,但是很多实现都是把前缀表统一减
|
||||
|
||||
其中n为文本串长度,m为模式串长度,因为在匹配的过程中,根据前缀表不断调整匹配的位置,可以看出匹配的过程是O(n),之前还要单独生成next数组,时间复杂度是O(m)。所以整个KMP算法的时间复杂度是O(n+m)的。
|
||||
|
||||
暴力的解法显而易见是O(n × m),所以**KMP在字符串匹配中极大的提高的搜索的效率。**
|
||||
暴力的解法显而易见是O(n × m),所以**KMP在字符串匹配中极大地提高了搜索的效率。**
|
||||
|
||||
为了和力扣题目28.实现strStr保持一致,方便大家理解,以下文章统称haystack为文本串, needle为模式串。
|
||||
|
||||
@ -251,7 +251,7 @@ void getNext(int* next, const string& s)
|
||||
2. 处理前后缀不相同的情况
|
||||
3. 处理前后缀相同的情况
|
||||
|
||||
接下来我们详解详解一下。
|
||||
接下来我们详解一下。
|
||||
|
||||
1. 初始化:
|
||||
|
||||
@ -613,12 +613,12 @@ class Solution {
|
||||
public void getNext(int[] next, String s){
|
||||
int j = -1;
|
||||
next[0] = j;
|
||||
for (int i = 1; i<s.length(); i++){
|
||||
while(j>=0 && s.charAt(i) != s.charAt(j+1)){
|
||||
for (int i = 1; i < s.length(); i++){
|
||||
while(j >= 0 && s.charAt(i) != s.charAt(j+1)){
|
||||
j=next[j];
|
||||
}
|
||||
|
||||
if(s.charAt(i)==s.charAt(j+1)){
|
||||
if(s.charAt(i) == s.charAt(j+1)){
|
||||
j++;
|
||||
}
|
||||
next[i] = j;
|
||||
@ -632,14 +632,14 @@ class Solution {
|
||||
int[] next = new int[needle.length()];
|
||||
getNext(next, needle);
|
||||
int j = -1;
|
||||
for(int i = 0; i<haystack.length();i++){
|
||||
for(int i = 0; i < haystack.length(); i++){
|
||||
while(j>=0 && haystack.charAt(i) != needle.charAt(j+1)){
|
||||
j = next[j];
|
||||
}
|
||||
if(haystack.charAt(i)==needle.charAt(j+1)){
|
||||
if(haystack.charAt(i) == needle.charAt(j+1)){
|
||||
j++;
|
||||
}
|
||||
if(j==needle.length()-1){
|
||||
if(j == needle.length()-1){
|
||||
return (i-needle.length()+1);
|
||||
}
|
||||
}
|
||||
@ -694,9 +694,9 @@ class Solution(object):
|
||||
:type needle: str
|
||||
:rtype: int
|
||||
"""
|
||||
m,n=len(haystack),len(needle)
|
||||
m, n = len(haystack), len(needle)
|
||||
for i in range(m):
|
||||
if haystack[i:i+n]==needle:
|
||||
if haystack[i:i+n] == needle:
|
||||
return i
|
||||
return -1
|
||||
```
|
||||
@ -704,31 +704,31 @@ class Solution(object):
|
||||
// 方法一
|
||||
class Solution:
|
||||
def strStr(self, haystack: str, needle: str) -> int:
|
||||
a=len(needle)
|
||||
b=len(haystack)
|
||||
if a==0:
|
||||
a = len(needle)
|
||||
b = len(haystack)
|
||||
if a == 0:
|
||||
return 0
|
||||
next=self.getnext(a,needle)
|
||||
next = self.getnext(a,needle)
|
||||
p=-1
|
||||
for j in range(b):
|
||||
while p>=0 and needle[p+1]!=haystack[j]:
|
||||
p=next[p]
|
||||
if needle[p+1]==haystack[j]:
|
||||
p+=1
|
||||
if p==a-1:
|
||||
while p >= 0 and needle[p+1] != haystack[j]:
|
||||
p = next[p]
|
||||
if needle[p+1] == haystack[j]:
|
||||
p += 1
|
||||
if p == a-1:
|
||||
return j-a+1
|
||||
return -1
|
||||
|
||||
def getnext(self,a,needle):
|
||||
next=['' for i in range(a)]
|
||||
k=-1
|
||||
next[0]=k
|
||||
for i in range(1,len(needle)):
|
||||
while (k>-1 and needle[k+1]!=needle[i]):
|
||||
k=next[k]
|
||||
if needle[k+1]==needle[i]:
|
||||
k+=1
|
||||
next[i]=k
|
||||
next = ['' for i in range(a)]
|
||||
k = -1
|
||||
next[0] = k
|
||||
for i in range(1, len(needle)):
|
||||
while (k > -1 and needle[k+1] != needle[i]):
|
||||
k = next[k]
|
||||
if needle[k+1] == needle[i]:
|
||||
k += 1
|
||||
next[i] = k
|
||||
return next
|
||||
```
|
||||
|
||||
@ -736,34 +736,34 @@ class Solution:
|
||||
// 方法二
|
||||
class Solution:
|
||||
def strStr(self, haystack: str, needle: str) -> int:
|
||||
a=len(needle)
|
||||
b=len(haystack)
|
||||
if a==0:
|
||||
a = len(needle)
|
||||
b = len(haystack)
|
||||
if a == 0:
|
||||
return 0
|
||||
i=j=0
|
||||
next=self.getnext(a,needle)
|
||||
while(i<b and j<a):
|
||||
if j==-1 or needle[j]==haystack[i]:
|
||||
i+=1
|
||||
j+=1
|
||||
i = j = 0
|
||||
next = self.getnext(a, needle)
|
||||
while(i < b and j < a):
|
||||
if j == -1 or needle[j] == haystack[i]:
|
||||
i += 1
|
||||
j += 1
|
||||
else:
|
||||
j=next[j]
|
||||
if j==a:
|
||||
j = next[j]
|
||||
if j == a:
|
||||
return i-j
|
||||
else:
|
||||
return -1
|
||||
|
||||
def getnext(self,a,needle):
|
||||
next=['' for i in range(a)]
|
||||
j,k=0,-1
|
||||
next[0]=k
|
||||
while(j<a-1):
|
||||
if k==-1 or needle[k]==needle[j]:
|
||||
k+=1
|
||||
j+=1
|
||||
next[j]=k
|
||||
def getnext(self, a, needle):
|
||||
next = ['' for i in range(a)]
|
||||
j, k = 0, -1
|
||||
next[0] = k
|
||||
while(j < a-1):
|
||||
if k == -1 or needle[k] == needle[j]:
|
||||
k += 1
|
||||
j += 1
|
||||
next[j] = k
|
||||
else:
|
||||
k=next[k]
|
||||
k = next[k]
|
||||
return next
|
||||
```
|
||||
|
||||
@ -777,17 +777,17 @@ Go:
|
||||
// next 前缀表数组
|
||||
// s 模式串
|
||||
func getNext(next []int, s string) {
|
||||
j := -1 // j表示 最长相等前后缀长度
|
||||
j := -1 // j表示 最长相等前后缀长度
|
||||
next[0] = j
|
||||
|
||||
for i := 1; i < len(s); i++ {
|
||||
for j >= 0 && s[i] != s[j+1] {
|
||||
j = next[j] // 回退前一位
|
||||
j = next[j] // 回退前一位
|
||||
}
|
||||
if s[i] == s[j+1] {
|
||||
j++
|
||||
}
|
||||
next[i] = j // next[i]是i(包括i)之前的最长相等前后缀长度
|
||||
next[i] = j // next[i]是i(包括i)之前的最长相等前后缀长度
|
||||
}
|
||||
}
|
||||
func strStr(haystack string, needle string) int {
|
||||
@ -796,15 +796,15 @@ func strStr(haystack string, needle string) int {
|
||||
}
|
||||
next := make([]int, len(needle))
|
||||
getNext(next, needle)
|
||||
j := -1 // 模式串的起始位置 next为-1 因此也为-1
|
||||
j := -1 // 模式串的起始位置 next为-1 因此也为-1
|
||||
for i := 0; i < len(haystack); i++ {
|
||||
for j >= 0 && haystack[i] != needle[j+1] {
|
||||
j = next[j] // 寻找下一个匹配点
|
||||
j = next[j] // 寻找下一个匹配点
|
||||
}
|
||||
if haystack[i] == needle[j+1] {
|
||||
j++
|
||||
}
|
||||
if j == len(needle)-1 { // j指向了模式串的末尾
|
||||
if j == len(needle)-1 { // j指向了模式串的末尾
|
||||
return i - len(needle) + 1
|
||||
}
|
||||
}
|
||||
@ -842,7 +842,7 @@ func strStr(haystack string, needle string) int {
|
||||
getNext(next, needle)
|
||||
for i := 0; i < len(haystack); i++ {
|
||||
for j > 0 && haystack[i] != needle[j] {
|
||||
j = next[j-1] // 回退到j的前一位
|
||||
j = next[j-1] // 回退到j的前一位
|
||||
}
|
||||
if haystack[i] == needle[j] {
|
||||
j++
|
||||
|
@ -271,6 +271,64 @@ class Solution {
|
||||
}
|
||||
```
|
||||
|
||||
```java
|
||||
// 解法三
|
||||
class Solution {
|
||||
public int[] searchRange(int[] nums, int target) {
|
||||
int left = searchLeft(nums,target);
|
||||
int right = searchRight(nums,target);
|
||||
return new int[]{left,right};
|
||||
}
|
||||
public int searchLeft(int[] nums,int target){
|
||||
// 寻找元素第一次出现的地方
|
||||
int left = 0;
|
||||
int right = nums.length-1;
|
||||
while(left<=right){
|
||||
int mid = left+(right-left)/2;
|
||||
// >= 的都要缩小 因为要找第一个元素
|
||||
if(nums[mid]>=target){
|
||||
right = mid - 1;
|
||||
}else{
|
||||
left = mid + 1;
|
||||
}
|
||||
}
|
||||
// right = left - 1
|
||||
// 如果存在答案 right是首选
|
||||
if(right>=0&&right<nums.length&&nums[right]==target){
|
||||
return right;
|
||||
}
|
||||
if(left>=0&&left<nums.length&&nums[left]==target){
|
||||
return left;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public int searchRight(int[] nums,int target){
|
||||
// 找最后一次出现
|
||||
int left = 0;
|
||||
int right = nums.length-1;
|
||||
while(left<=right){
|
||||
int mid = left + (right-left)/2;
|
||||
// <= 的都要更新 因为我们要找最后一个元素
|
||||
if(nums[mid]<=target){
|
||||
left = mid + 1;
|
||||
}else{
|
||||
right = mid - 1;
|
||||
}
|
||||
}
|
||||
// left = right + 1
|
||||
// 要找最后一次出现 如果有答案 优先找left
|
||||
if(left>=0&&left<nums.length&&nums[left]==target){
|
||||
return left;
|
||||
}
|
||||
if(right>=0&&right<=nums.length&&nums[right]==target){
|
||||
return right;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### Python
|
||||
@ -685,3 +743,4 @@ class Solution {
|
||||
<a href="https://programmercarl.com/other/kstar.html" target="_blank">
|
||||
<img src="../pics/网站星球宣传海报.jpg" width="1000"/>
|
||||
</a>
|
||||
|
||||
|
@ -119,6 +119,19 @@ class Solution:
|
||||
return False
|
||||
```
|
||||
|
||||
```python
|
||||
## for循环
|
||||
class Solution:
|
||||
def canJump(self, nums: List[int]) -> bool:
|
||||
cover = 0
|
||||
if len(nums) == 1: return True
|
||||
for i in range(len(nums)):
|
||||
if i <= cover:
|
||||
cover = max(i + nums[i], cover)
|
||||
if cover >= len(nums) - 1: return True
|
||||
return False
|
||||
```
|
||||
|
||||
### Go
|
||||
```Go
|
||||
func canJUmp(nums []int) bool {
|
||||
|
@ -272,24 +272,28 @@ class Solution:
|
||||
row = len(obstacleGrid)
|
||||
col = len(obstacleGrid[0])
|
||||
dp = [[0 for _ in range(col)] for _ in range(row)]
|
||||
|
||||
dp[0][0] = 1 if obstacleGrid[0][0] != 1 else 0
|
||||
if dp[0][0] == 0: return 0 # 如果第一个格子就是障碍,return 0
|
||||
dp[0][0] = 0 if obstacleGrid[0][0] == 1 else 1
|
||||
if dp[0][0] == 0:
|
||||
return 0 # 如果第一个格子就是障碍,return 0
|
||||
# 第一行
|
||||
for i in range(1, col):
|
||||
if obstacleGrid[0][i] != 1:
|
||||
dp[0][i] = dp[0][i-1]
|
||||
if obstacleGrid[0][i] == 1:
|
||||
# 遇到障碍物时,直接退出循环,后面默认都是0
|
||||
break
|
||||
dp[0][i] = 1
|
||||
|
||||
# 第一列
|
||||
for i in range(1, row):
|
||||
if obstacleGrid[i][0] != 1:
|
||||
dp[i][0] = dp[i-1][0]
|
||||
print(dp)
|
||||
if obstacleGrid[i][0] == 1:
|
||||
# 遇到障碍物时,直接退出循环,后面默认都是0
|
||||
break
|
||||
dp[i][0] = 1
|
||||
# print(dp)
|
||||
|
||||
for i in range(1, row):
|
||||
for j in range(1, col):
|
||||
if obstacleGrid[i][j] != 1:
|
||||
dp[i][j] = dp[i-1][j] + dp[i][j-1]
|
||||
if obstacleGrid[i][j] == 0:
|
||||
dp[i][j] = dp[i - 1][j] + dp[i][j - 1]
|
||||
return dp[-1][-1]
|
||||
```
|
||||
|
||||
|
@ -206,7 +206,7 @@ class Solution {
|
||||
public int largestRectangleArea(int[] heights) {
|
||||
int length = heights.length;
|
||||
int[] minLeftIndex = new int [length];
|
||||
int[] maxRigthIndex = new int [length];
|
||||
int[] minRightIndex = new int [length];
|
||||
// 记录左边第一个小于该柱子的下标
|
||||
minLeftIndex[0] = -1 ;
|
||||
for (int i = 1; i < length; i++) {
|
||||
@ -215,17 +215,17 @@ class Solution {
|
||||
while (t >= 0 && heights[t] >= heights[i]) t = minLeftIndex[t];
|
||||
minLeftIndex[i] = t;
|
||||
}
|
||||
// 记录每个柱子 右边第一个小于该柱子的下标
|
||||
maxRigthIndex[length - 1] = length;
|
||||
// 记录每个柱子右边第一个小于该柱子的下标
|
||||
minRightIndex[length - 1] = length;
|
||||
for (int i = length - 2; i >= 0; i--) {
|
||||
int t = i + 1;
|
||||
while(t < length && heights[t] >= heights[i]) t = maxRigthIndex[t];
|
||||
maxRigthIndex[i] = t;
|
||||
while(t < length && heights[t] >= heights[i]) t = minRightIndex[t];
|
||||
minRightIndex[i] = t;
|
||||
}
|
||||
// 求和
|
||||
int result = 0;
|
||||
for (int i = 0; i < length; i++) {
|
||||
int sum = heights[i] * (maxRigthIndex[i] - minLeftIndex[i] - 1);
|
||||
int sum = heights[i] * (minRightIndex[i] - minLeftIndex[i] - 1);
|
||||
result = Math.max(sum, result);
|
||||
}
|
||||
return result;
|
||||
|
@ -754,23 +754,138 @@ func isSymmetric3(_ root: TreeNode?) -> Bool {
|
||||
|
||||
## Scala
|
||||
|
||||
递归:
|
||||
> 递归:
|
||||
```scala
|
||||
object Solution {
|
||||
object Solution {
|
||||
def isSymmetric(root: TreeNode): Boolean = {
|
||||
if (root == null) return true // 如果等于空直接返回true
|
||||
|
||||
def compare(left: TreeNode, right: TreeNode): Boolean = {
|
||||
if (left == null && right == null) return true // 如果左右都为空,则为true
|
||||
if (left == null && right != null) return false // 如果左空右不空,不对称,返回false
|
||||
if (left != null && right == null) return false // 如果左不空右空,不对称,返回false
|
||||
if (left == null && right == null) true // 如果左右都为空,则为true
|
||||
else if (left == null && right != null) false // 如果左空右不空,不对称,返回false
|
||||
else if (left != null && right == null) false // 如果左不空右空,不对称,返回false
|
||||
// 如果左右的值相等,并且往下递归
|
||||
left.value == right.value && compare(left.left, right.right) && compare(left.right, right.left)
|
||||
else left.value == right.value && compare(left.left, right.right) && compare(left.right, right.left)
|
||||
}
|
||||
|
||||
// 分别比较左子树和右子树
|
||||
compare(root.left, root.right)
|
||||
}
|
||||
}
|
||||
```
|
||||
> 迭代 - 使用栈
|
||||
```scala
|
||||
object Solution {
|
||||
|
||||
import scala.collection.mutable
|
||||
|
||||
def isSymmetric(root: TreeNode): Boolean = {
|
||||
if (root == null) return true
|
||||
|
||||
val cache = mutable.Stack[(TreeNode, TreeNode)]((root.left, root.right))
|
||||
|
||||
while (cache.nonEmpty) {
|
||||
cache.pop() match {
|
||||
case (null, null) =>
|
||||
case (_, null) => return false
|
||||
case (null, _) => return false
|
||||
case (left, right) =>
|
||||
if (left.value != right.value) return false
|
||||
cache.push((left.left, right.right))
|
||||
cache.push((left.right, right.left))
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
}
|
||||
```
|
||||
> 迭代 - 使用队列
|
||||
```scala
|
||||
object Solution {
|
||||
|
||||
import scala.collection.mutable
|
||||
|
||||
def isSymmetric(root: TreeNode): Boolean = {
|
||||
if (root == null) return true
|
||||
|
||||
val cache = mutable.Queue[(TreeNode, TreeNode)]((root.left, root.right))
|
||||
|
||||
while (cache.nonEmpty) {
|
||||
cache.dequeue() match {
|
||||
case (null, null) =>
|
||||
case (_, null) => return false
|
||||
case (null, _) => return false
|
||||
case (left, right) =>
|
||||
if (left.value != right.value) return false
|
||||
cache.enqueue((left.left, right.right))
|
||||
cache.enqueue((left.right, right.left))
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Rust
|
||||
|
||||
递归:
|
||||
```rust
|
||||
impl Solution {
|
||||
pub fn is_symmetric(root: Option<Rc<RefCell<TreeNode>>>) -> bool {
|
||||
Self::recur(
|
||||
&root.as_ref().unwrap().borrow().left,
|
||||
&root.as_ref().unwrap().borrow().right,
|
||||
)
|
||||
}
|
||||
pub fn recur(
|
||||
left: &Option<Rc<RefCell<TreeNode>>>,
|
||||
right: &Option<Rc<RefCell<TreeNode>>>,
|
||||
) -> bool {
|
||||
match (left, right) {
|
||||
(None, None) => true,
|
||||
(Some(n1), Some(n2)) => {
|
||||
return n1.borrow().val == n2.borrow().val
|
||||
&& Self::recur(&n1.borrow().left, &n2.borrow().right)
|
||||
&& Self::recur(&n1.borrow().right, &n2.borrow().left)
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
迭代:
|
||||
```rust
|
||||
use std::cell::RefCell;
|
||||
use std::collections::VecDeque;
|
||||
use std::rc::Rc;
|
||||
impl Solution {
|
||||
pub fn is_symmetric(root: Option<Rc<RefCell<TreeNode>>>) -> bool {
|
||||
let mut queue = VecDeque::new();
|
||||
if let Some(node) = root {
|
||||
queue.push_back(node.borrow().left.clone());
|
||||
queue.push_back(node.borrow().right.clone());
|
||||
}
|
||||
while !queue.is_empty() {
|
||||
let (n1, n2) = (queue.pop_front().unwrap(), queue.pop_front().unwrap());
|
||||
match (n1.clone(), n2.clone()) {
|
||||
(None, None) => continue,
|
||||
(Some(n1), Some(n2)) => {
|
||||
if n1.borrow().val != n2.borrow().val {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
_ => return false,
|
||||
};
|
||||
queue.push_back(n1.as_ref().unwrap().borrow().left.clone());
|
||||
queue.push_back(n2.as_ref().unwrap().borrow().right.clone());
|
||||
queue.push_back(n1.unwrap().borrow().right.clone());
|
||||
queue.push_back(n2.unwrap().borrow().left.clone());
|
||||
}
|
||||
true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
<p align="center">
|
||||
<a href="https://programmercarl.com/other/kstar.html" target="_blank">
|
||||
|
@ -380,29 +380,32 @@ object Solution {
|
||||
Rust:
|
||||
|
||||
```rust
|
||||
pub fn level_order(root: Option<Rc<RefCell<TreeNode>>>) -> Vec<Vec<i32>> {
|
||||
let mut ans = Vec::new();
|
||||
let mut stack = Vec::new();
|
||||
if root.is_none(){
|
||||
return ans;
|
||||
}
|
||||
stack.push(root.unwrap());
|
||||
while stack.is_empty()!= true{
|
||||
let num = stack.len();
|
||||
let mut level = Vec::new();
|
||||
for _i in 0..num{
|
||||
let tmp = stack.remove(0);
|
||||
level.push(tmp.borrow_mut().val);
|
||||
if tmp.borrow_mut().left.is_some(){
|
||||
stack.push(tmp.borrow_mut().left.take().unwrap());
|
||||
}
|
||||
if tmp.borrow_mut().right.is_some(){
|
||||
stack.push(tmp.borrow_mut().right.take().unwrap());
|
||||
}
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
use std::collections::VecDeque;
|
||||
impl Solution {
|
||||
pub fn level_order(root: Option<Rc<RefCell<TreeNode>>>) -> Vec<Vec<i32>> {
|
||||
let mut res = vec![];
|
||||
let mut queue = VecDeque::new();
|
||||
if root.is_some() {
|
||||
queue.push_back(root);
|
||||
}
|
||||
ans.push(level);
|
||||
while !queue.is_empty() {
|
||||
let mut temp = vec![];
|
||||
for _ in 0..queue.len() {
|
||||
let node = queue.pop_front().unwrap().unwrap();
|
||||
temp.push(node.borrow().val);
|
||||
if node.borrow().left.is_some() {
|
||||
queue.push_back(node.borrow().left.clone());
|
||||
}
|
||||
if node.borrow().right.is_some() {
|
||||
queue.push_back(node.borrow().right.clone());
|
||||
}
|
||||
}
|
||||
res.push(temp);
|
||||
}
|
||||
res
|
||||
}
|
||||
ans
|
||||
}
|
||||
```
|
||||
|
||||
@ -665,29 +668,32 @@ object Solution {
|
||||
Rust:
|
||||
|
||||
```rust
|
||||
pub fn level_order(root: Option<Rc<RefCell<TreeNode>>>) -> Vec<Vec<i32>> {
|
||||
let mut ans = Vec::new();
|
||||
let mut stack = Vec::new();
|
||||
if root.is_none(){
|
||||
return ans;
|
||||
}
|
||||
stack.push(root.unwrap());
|
||||
while stack.is_empty()!= true{
|
||||
let num = stack.len();
|
||||
let mut level = Vec::new();
|
||||
for _i in 0..num{
|
||||
let tmp = stack.remove(0);
|
||||
level.push(tmp.borrow_mut().val);
|
||||
if tmp.borrow_mut().left.is_some(){
|
||||
stack.push(tmp.borrow_mut().left.take().unwrap());
|
||||
}
|
||||
if tmp.borrow_mut().right.is_some(){
|
||||
stack.push(tmp.borrow_mut().right.take().unwrap());
|
||||
}
|
||||
use std::cell::RefCell;
|
||||
use std::collections::VecDeque;
|
||||
use std::rc::Rc;
|
||||
impl Solution {
|
||||
pub fn level_order_bottom(root: Option<Rc<RefCell<TreeNode>>>) -> Vec<Vec<i32>> {
|
||||
let mut res = vec![];
|
||||
let mut queue = VecDeque::new();
|
||||
if root.is_some() {
|
||||
queue.push_back(root);
|
||||
}
|
||||
ans.push(level);
|
||||
while !queue.is_empty() {
|
||||
let mut temp = vec![];
|
||||
for _ in 0..queue.len() {
|
||||
let node = queue.pop_front().unwrap().unwrap();
|
||||
temp.push(node.borrow().val);
|
||||
if node.borrow().left.is_some() {
|
||||
queue.push_back(node.borrow().left.clone());
|
||||
}
|
||||
if node.borrow().right.is_some() {
|
||||
queue.push_back(node.borrow().right.clone());
|
||||
}
|
||||
}
|
||||
res.push(temp);
|
||||
}
|
||||
res.into_iter().rev().collect()
|
||||
}
|
||||
ans
|
||||
}
|
||||
```
|
||||
|
||||
@ -935,6 +941,39 @@ object Solution {
|
||||
}
|
||||
```
|
||||
|
||||
rust:
|
||||
|
||||
```rust
|
||||
use std::cell::RefCell;
|
||||
use std::collections::VecDeque;
|
||||
use std::rc::Rc;
|
||||
impl Solution {
|
||||
pub fn right_side_view(root: Option<Rc<RefCell<TreeNode>>>) -> Vec<i32> {
|
||||
let mut res = vec![];
|
||||
let mut queue = VecDeque::new();
|
||||
if root.is_some() {
|
||||
queue.push_back(root);
|
||||
}
|
||||
while !queue.is_empty() {
|
||||
let len = queue.len();
|
||||
for i in 0..len {
|
||||
let node = queue.pop_front().unwrap().unwrap();
|
||||
if i == len - 1 {
|
||||
res.push(node.borrow().val);
|
||||
}
|
||||
if node.borrow().left.is_some() {
|
||||
queue.push_back(node.borrow().left.clone());
|
||||
}
|
||||
if node.borrow().right.is_some() {
|
||||
queue.push_back(node.borrow().right.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
res
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
# 637.二叉树的层平均值
|
||||
|
||||
[力扣题目链接](https://leetcode.cn/problems/average-of-levels-in-binary-tree/)
|
||||
@ -1185,6 +1224,39 @@ object Solution {
|
||||
}
|
||||
```
|
||||
|
||||
rust:
|
||||
|
||||
```rust
|
||||
use std::cell::RefCell;
|
||||
use std::collections::VecDeque;
|
||||
use std::rc::Rc;
|
||||
impl Solution {
|
||||
pub fn average_of_levels(root: Option<Rc<RefCell<TreeNode>>>) -> Vec<f64> {
|
||||
let mut res = vec![];
|
||||
let mut queue = VecDeque::new();
|
||||
if root.is_some() {
|
||||
queue.push_back(root);
|
||||
}
|
||||
while !queue.is_empty() {
|
||||
let len = queue.len();
|
||||
let mut sum = 0;
|
||||
for _ in 0..len {
|
||||
let node = queue.pop_front().unwrap().unwrap();
|
||||
sum += node.borrow().val;
|
||||
if node.borrow().left.is_some() {
|
||||
queue.push_back(node.borrow().left.clone());
|
||||
}
|
||||
if node.borrow().right.is_some() {
|
||||
queue.push_back(node.borrow().right.clone());
|
||||
}
|
||||
}
|
||||
res.push((sum as f64) / len as f64);
|
||||
}
|
||||
res
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
# 429.N叉树的层序遍历
|
||||
|
||||
[力扣题目链接](https://leetcode.cn/problems/n-ary-tree-level-order-traversal/)
|
||||
@ -1456,6 +1528,54 @@ object Solution {
|
||||
}
|
||||
```
|
||||
|
||||
rust:
|
||||
|
||||
```rust
|
||||
pub struct Solution;
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub struct Node {
|
||||
pub val: i32,
|
||||
pub children: Vec<Option<Rc<RefCell<Node>>>>,
|
||||
}
|
||||
|
||||
impl Node {
|
||||
#[inline]
|
||||
pub fn new(val: i32) -> Node {
|
||||
Node {
|
||||
val,
|
||||
children: vec![],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
use std::cell::RefCell;
|
||||
use std::collections::VecDeque;
|
||||
use std::rc::Rc;
|
||||
impl Solution {
|
||||
pub fn level_order(root: Option<Rc<RefCell<Node>>>) -> Vec<Vec<i32>> {
|
||||
let mut res = vec![];
|
||||
let mut queue = VecDeque::new();
|
||||
if root.is_some() {
|
||||
queue.push_back(root);
|
||||
}
|
||||
while !queue.is_empty() {
|
||||
let mut temp = vec![];
|
||||
for _ in 0..queue.len() {
|
||||
let node = queue.pop_front().unwrap().unwrap();
|
||||
temp.push(node.borrow().val);
|
||||
if !node.borrow().children.is_empty() {
|
||||
for n in node.borrow().children.clone() {
|
||||
queue.push_back(n);
|
||||
}
|
||||
}
|
||||
}
|
||||
res.push(temp)
|
||||
}
|
||||
res
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
# 515.在每个树行中找最大值
|
||||
|
||||
[力扣题目链接](https://leetcode.cn/problems/find-largest-value-in-each-tree-row/)
|
||||
@ -1686,6 +1806,38 @@ object Solution {
|
||||
}
|
||||
```
|
||||
|
||||
rust:
|
||||
|
||||
```rust
|
||||
use std::cell::RefCell;
|
||||
use std::collections::VecDeque;
|
||||
use std::rc::Rc;
|
||||
impl Solution {
|
||||
pub fn largest_values(root: Option<Rc<RefCell<TreeNode>>>) -> Vec<i32> {
|
||||
let mut res = vec![];
|
||||
let mut queue = VecDeque::new();
|
||||
if root.is_some() {
|
||||
queue.push_back(root);
|
||||
}
|
||||
while !queue.is_empty() {
|
||||
let mut max = i32::MIN;
|
||||
for _ in 0..queue.len() {
|
||||
let node = queue.pop_front().unwrap().unwrap();
|
||||
max = max.max(node.borrow().val);
|
||||
if node.borrow().left.is_some() {
|
||||
queue.push_back(node.borrow().left.clone());
|
||||
}
|
||||
if node.borrow().right.is_some() {
|
||||
queue.push_back(node.borrow().right.clone());
|
||||
}
|
||||
}
|
||||
res.push(max);
|
||||
}
|
||||
res
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
# 116.填充每个节点的下一个右侧节点指针
|
||||
|
||||
[力扣题目链接](https://leetcode.cn/problems/populating-next-right-pointers-in-each-node/)
|
||||
@ -2472,6 +2624,36 @@ object Solution {
|
||||
}
|
||||
```
|
||||
|
||||
rust:
|
||||
|
||||
```rust
|
||||
use std::cell::RefCell;
|
||||
use std::collections::VecDeque;
|
||||
use std::rc::Rc;
|
||||
impl Solution {
|
||||
pub fn max_depth(root: Option<Rc<RefCell<TreeNode>>>) -> i32 {
|
||||
let mut queue = VecDeque::new();
|
||||
let mut res = 0;
|
||||
if root.is_some() {
|
||||
queue.push_back(root);
|
||||
}
|
||||
while !queue.is_empty() {
|
||||
res += 1;
|
||||
for _ in 0..queue.len() {
|
||||
let node = queue.pop_front().unwrap().unwrap();
|
||||
if node.borrow().left.is_some() {
|
||||
queue.push_back(node.borrow().left.clone());
|
||||
}
|
||||
if node.borrow().right.is_some() {
|
||||
queue.push_back(node.borrow().right.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
res
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
# 111.二叉树的最小深度
|
||||
|
||||
[力扣题目链接](https://leetcode.cn/problems/minimum-depth-of-binary-tree/)
|
||||
@ -2716,6 +2898,39 @@ object Solution {
|
||||
}
|
||||
```
|
||||
|
||||
rust:
|
||||
|
||||
```rust
|
||||
use std::cell::RefCell;
|
||||
use std::collections::VecDeque;
|
||||
use std::rc::Rc;
|
||||
impl Solution {
|
||||
pub fn min_depth(root: Option<Rc<RefCell<TreeNode>>>) -> i32 {
|
||||
let mut res = 0;
|
||||
let mut queue = VecDeque::new();
|
||||
if root.is_some() {
|
||||
queue.push_back(root);
|
||||
}
|
||||
while !queue.is_empty() {
|
||||
res += 1;
|
||||
for _ in 0..queue.len() {
|
||||
let node = queue.pop_front().unwrap().unwrap();
|
||||
if node.borrow().left.is_none() && node.borrow().right.is_none() {
|
||||
return res;
|
||||
}
|
||||
if node.borrow().left.is_some() {
|
||||
queue.push_back(node.borrow().left.clone());
|
||||
}
|
||||
if node.borrow().right.is_some() {
|
||||
queue.push_back(node.borrow().right.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
res
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
# 总结
|
||||
|
||||
二叉树的层序遍历,**就是图论中的广度优先搜索在二叉树中的应用**,需要借助队列来实现(此时又发现队列的一个应用了)。
|
||||
|
@ -200,32 +200,6 @@ public:
|
||||
};
|
||||
```
|
||||
|
||||
rust:
|
||||
```rust
|
||||
impl Solution {
|
||||
pub fn max_depth(root: Option<Rc<RefCell<TreeNode>>>) -> i32 {
|
||||
if root.is_none(){
|
||||
return 0;
|
||||
}
|
||||
let mut max_depth: i32 = 0;
|
||||
let mut stack = vec![root.unwrap()];
|
||||
while !stack.is_empty() {
|
||||
let num = stack.len();
|
||||
for _i in 0..num{
|
||||
let top = stack.remove(0);
|
||||
if top.borrow_mut().left.is_some(){
|
||||
stack.push(top.borrow_mut().left.take().unwrap());
|
||||
}
|
||||
if top.borrow_mut().right.is_some(){
|
||||
stack.push(top.borrow_mut().right.take().unwrap());
|
||||
}
|
||||
}
|
||||
max_depth+=1;
|
||||
}
|
||||
max_depth
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
那么我们可以顺便解决一下n叉树的最大深度问题
|
||||
|
||||
@ -975,6 +949,50 @@ object Solution {
|
||||
}
|
||||
```
|
||||
|
||||
## rust
|
||||
### 0104.二叉树的最大深度
|
||||
|
||||
递归:
|
||||
```rust
|
||||
impl Solution {
|
||||
pub fn max_depth(root: Option<Rc<RefCell<TreeNode>>>) -> i32 {
|
||||
if root.is_none() {
|
||||
return 0;
|
||||
}
|
||||
std::cmp::max(
|
||||
Self::max_depth(root.clone().unwrap().borrow().left.clone()),
|
||||
Self::max_depth(root.unwrap().borrow().right.clone()),
|
||||
) + 1
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
迭代:
|
||||
```rust
|
||||
impl Solution {
|
||||
pub fn max_depth(root: Option<Rc<RefCell<TreeNode>>>) -> i32 {
|
||||
if root.is_none(){
|
||||
return 0;
|
||||
}
|
||||
let mut max_depth: i32 = 0;
|
||||
let mut stack = vec![root.unwrap()];
|
||||
while !stack.is_empty() {
|
||||
let num = stack.len();
|
||||
for _i in 0..num{
|
||||
let top = stack.remove(0);
|
||||
if top.borrow_mut().left.is_some(){
|
||||
stack.push(top.borrow_mut().left.take().unwrap());
|
||||
}
|
||||
if top.borrow_mut().right.is_some(){
|
||||
stack.push(top.borrow_mut().right.take().unwrap());
|
||||
}
|
||||
}
|
||||
max_depth+=1;
|
||||
}
|
||||
max_depth
|
||||
}
|
||||
```
|
||||
|
||||
<p align="center">
|
||||
<a href="https://programmercarl.com/other/kstar.html" target="_blank">
|
||||
<img src="../pics/网站星球宣传海报.jpg" width="1000"/>
|
||||
|
@ -310,6 +310,18 @@ class Solution:
|
||||
return dp[(length-1) % 2][1]
|
||||
```
|
||||
|
||||
> 动态规划:版本三
|
||||
```python
|
||||
class Solution:
|
||||
def maxProfit(self, prices: List[int]) -> int:
|
||||
length = len(prices)
|
||||
dp0, dp1 = -prices[0], 0 #注意这里只维护两个常量,因为dp0的更新不受dp1的影响
|
||||
for i in range(1, length):
|
||||
dp1 = max(dp1, dp0 + prices[i])
|
||||
dp0 = max(dp0, -prices[i])
|
||||
return dp1
|
||||
```
|
||||
|
||||
Go:
|
||||
> 贪心法:
|
||||
```Go
|
||||
|
@ -420,6 +420,41 @@ object Solution {
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
rust:
|
||||
|
||||
```rust
|
||||
impl Solution {
|
||||
pub fn eval_rpn(tokens: Vec<String>) -> i32 {
|
||||
let mut stack = vec![];
|
||||
for token in tokens.into_iter() {
|
||||
match token.as_str() {
|
||||
"+" => {
|
||||
let a = stack.pop().unwrap();
|
||||
*stack.last_mut().unwrap() += a;
|
||||
}
|
||||
"-" => {
|
||||
let a = stack.pop().unwrap();
|
||||
*stack.last_mut().unwrap() -= a;
|
||||
}
|
||||
"*" => {
|
||||
let a = stack.pop().unwrap();
|
||||
*stack.last_mut().unwrap() *= a;
|
||||
}
|
||||
"/" => {
|
||||
let a = stack.pop().unwrap();
|
||||
*stack.last_mut().unwrap() /= a;
|
||||
}
|
||||
_ => {
|
||||
stack.push(token.parse::<i32>().unwrap());
|
||||
}
|
||||
}
|
||||
}
|
||||
stack.pop().unwrap()
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
<p align="center">
|
||||
<a href="https://programmercarl.com/other/kstar.html" target="_blank">
|
||||
<img src="../pics/网站星球宣传海报.jpg" width="1000"/>
|
||||
|
@ -119,7 +119,7 @@ void removeExtraSpaces(string& s) {
|
||||
1. leetcode上的测试集里,字符串的长度不够长,如果足够长,性能差距会非常明显。
|
||||
2. leetcode的测程序耗时不是很准确的。
|
||||
|
||||
版本一的代码是比较如何一般思考过程,就是 先移除字符串钱的空格,在移除中间的,在移除后面部分。
|
||||
版本一的代码是一般的思考过程,就是 先移除字符串前的空格,再移除中间的,再移除后面部分。
|
||||
|
||||
不过其实还可以优化,这部分和[27.移除元素](https://programmercarl.com/0027.移除元素.html)的逻辑是一样一样的,本题是移除空格,而 27.移除元素 就是移除元素。
|
||||
|
||||
@ -145,7 +145,7 @@ void removeExtraSpaces(string& s) {//去除所有空格并在相邻单词之间
|
||||
|
||||
此时我们已经实现了removeExtraSpaces函数来移除冗余空格。
|
||||
|
||||
还做实现反转字符串的功能,支持反转字符串子区间,这个实现我们分别在[344.反转字符串](https://programmercarl.com/0344.反转字符串.html)和[541.反转字符串II](https://programmercarl.com/0541.反转字符串II.html)里已经讲过了。
|
||||
还要实现反转字符串的功能,支持反转字符串子区间,这个实现我们分别在[344.反转字符串](https://programmercarl.com/0344.反转字符串.html)和[541.反转字符串II](https://programmercarl.com/0541.反转字符串II.html)里已经讲过了。
|
||||
|
||||
代码如下:
|
||||
|
||||
@ -434,49 +434,51 @@ python:
|
||||
```Python
|
||||
class Solution:
|
||||
#1.去除多余的空格
|
||||
def trim_spaces(self,s):
|
||||
n=len(s)
|
||||
left=0
|
||||
right=n-1
|
||||
def trim_spaces(self, s):
|
||||
n = len(s)
|
||||
left = 0
|
||||
right = n-1
|
||||
|
||||
while left<=right and s[left]==' ': #去除开头的空格
|
||||
left+=1
|
||||
while left<=right and s[right]==' ': #去除结尾的空格
|
||||
right=right-1
|
||||
tmp=[]
|
||||
while left<=right: #去除单词中间多余的空格
|
||||
if s[left]!=' ':
|
||||
while left <= right and s[left] == ' ': #去除开头的空格
|
||||
left += 1
|
||||
while left <= right and s[right] == ' ': #去除结尾的空格
|
||||
right = right-1
|
||||
tmp = []
|
||||
while left <= right: #去除单词中间多余的空格
|
||||
if s[left] != ' ':
|
||||
tmp.append(s[left])
|
||||
elif tmp[-1]!=' ': #当前位置是空格,但是相邻的上一个位置不是空格,则该空格是合理的
|
||||
elif tmp[-1] != ' ': #当前位置是空格,但是相邻的上一个位置不是空格,则该空格是合理的
|
||||
tmp.append(s[left])
|
||||
left+=1
|
||||
left += 1
|
||||
return tmp
|
||||
#2.翻转字符数组
|
||||
def reverse_string(self,nums,left,right):
|
||||
while left<right:
|
||||
nums[left], nums[right]=nums[right],nums[left]
|
||||
left+=1
|
||||
right-=1
|
||||
|
||||
#2.翻转字符数组
|
||||
def reverse_string(self, nums, left, right):
|
||||
while left < right:
|
||||
nums[left], nums[right] = nums[right], nums[left]
|
||||
left += 1
|
||||
right -= 1
|
||||
return None
|
||||
#3.翻转每个单词
|
||||
|
||||
#3.翻转每个单词
|
||||
def reverse_each_word(self, nums):
|
||||
start=0
|
||||
end=0
|
||||
n=len(nums)
|
||||
while start<n:
|
||||
while end<n and nums[end]!=' ':
|
||||
end+=1
|
||||
self.reverse_string(nums,start,end-1)
|
||||
start=end+1
|
||||
end+=1
|
||||
start = 0
|
||||
end = 0
|
||||
n = len(nums)
|
||||
while start < n:
|
||||
while end < n and nums[end] != ' ':
|
||||
end += 1
|
||||
self.reverse_string(nums, start, end-1)
|
||||
start = end + 1
|
||||
end += 1
|
||||
return None
|
||||
|
||||
#4.翻转字符串里的单词
|
||||
def reverseWords(self, s): #测试用例:"the sky is blue"
|
||||
l = self.trim_spaces(s) #输出:['t', 'h', 'e', ' ', 's', 'k', 'y', ' ', 'i', 's', ' ', 'b', 'l', 'u', 'e'
|
||||
self.reverse_string( l, 0, len(l) - 1) #输出:['e', 'u', 'l', 'b', ' ', 's', 'i', ' ', 'y', 'k', 's', ' ', 'e', 'h', 't']
|
||||
self.reverse_each_word(l) #输出:['b', 'l', 'u', 'e', ' ', 'i', 's', ' ', 's', 'k', 'y', ' ', 't', 'h', 'e']
|
||||
return ''.join(l) #输出:blue is sky the
|
||||
def reverseWords(self, s): #测试用例:"the sky is blue"
|
||||
l = self.trim_spaces(s) #输出:['t', 'h', 'e', ' ', 's', 'k', 'y', ' ', 'i', 's', ' ', 'b', 'l', 'u', 'e'
|
||||
self.reverse_string(l, 0, len(l)-1) #输出:['e', 'u', 'l', 'b', ' ', 's', 'i', ' ', 'y', 'k', 's', ' ', 'e', 'h', 't']
|
||||
self.reverse_each_word(l) #输出:['b', 'l', 'u', 'e', ' ', 'i', 's', ' ', 's', 'k', 'y', ' ', 't', 'h', 'e']
|
||||
return ''.join(l) #输出:blue is sky the
|
||||
|
||||
|
||||
```
|
||||
|
@ -169,39 +169,18 @@ Python:
|
||||
```python
|
||||
class Solution:
|
||||
def minSubArrayLen(self, s: int, nums: List[int]) -> int:
|
||||
# 定义一个无限大的数
|
||||
res = float("inf")
|
||||
Sum = 0
|
||||
index = 0
|
||||
for i in range(len(nums)):
|
||||
Sum += nums[i]
|
||||
res = float("inf") # 定义一个无限大的数
|
||||
Sum = 0 # 滑动窗口数值之和
|
||||
i = 0 # 滑动窗口起始位置
|
||||
for j in range(len(nums)):
|
||||
Sum += nums[j]
|
||||
while Sum >= s:
|
||||
res = min(res, i-index+1)
|
||||
Sum -= nums[index]
|
||||
index += 1
|
||||
return 0 if res==float("inf") else res
|
||||
```
|
||||
```python
|
||||
# 滑动窗口
|
||||
class Solution:
|
||||
def minSubArrayLen(self, target: int, nums: List[int]) -> int:
|
||||
if nums is None or len(nums) == 0:
|
||||
return 0
|
||||
lenf = len(nums) + 1
|
||||
total = 0
|
||||
i = j = 0
|
||||
while (j < len(nums)):
|
||||
total = total + nums[j]
|
||||
j += 1
|
||||
while (total >= target):
|
||||
lenf = min(lenf, j - i)
|
||||
total = total - nums[i]
|
||||
res = min(res, j-i+1)
|
||||
Sum -= nums[i]
|
||||
i += 1
|
||||
if lenf == len(nums) + 1:
|
||||
return 0
|
||||
else:
|
||||
return lenf
|
||||
return 0 if res == float("inf") else res
|
||||
```
|
||||
|
||||
Go:
|
||||
```go
|
||||
func minSubArrayLen(target int, nums []int) int {
|
||||
@ -232,22 +211,23 @@ func minSubArrayLen(target int, nums []int) int {
|
||||
JavaScript:
|
||||
|
||||
```js
|
||||
|
||||
var minSubArrayLen = function(target, nums) {
|
||||
// 长度计算一次
|
||||
const len = nums.length;
|
||||
let l = r = sum = 0,
|
||||
res = len + 1; // 子数组最大不会超过自身
|
||||
while(r < len) {
|
||||
sum += nums[r++];
|
||||
// 窗口滑动
|
||||
while(sum >= target) {
|
||||
// r始终为开区间 [l, r)
|
||||
res = res < r - l ? res : r - l;
|
||||
sum-=nums[l++];
|
||||
let start, end
|
||||
start = end = 0
|
||||
let sum = 0
|
||||
let len = nums.length
|
||||
let ans = Infinity
|
||||
|
||||
while(end < len){
|
||||
sum += nums[end];
|
||||
while (sum >= target) {
|
||||
ans = Math.min(ans, end - start + 1);
|
||||
sum -= nums[start];
|
||||
start++;
|
||||
}
|
||||
end++;
|
||||
}
|
||||
return res > len ? 0 : res;
|
||||
return ans === Infinity ? 0 : ans
|
||||
};
|
||||
```
|
||||
|
||||
|
@ -1018,7 +1018,7 @@ class MyStack {
|
||||
}
|
||||
}
|
||||
```
|
||||
> 单对列
|
||||
> 单队列
|
||||
```php
|
||||
class MyStack {
|
||||
public $queue;
|
||||
@ -1051,6 +1051,44 @@ class MyStack {
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
> rust:单队列
|
||||
|
||||
```rust
|
||||
struct MyStack {
|
||||
queue: Vec<i32>,
|
||||
}
|
||||
|
||||
impl MyStack {
|
||||
fn new() -> Self {
|
||||
MyStack { queue: vec![] }
|
||||
}
|
||||
|
||||
fn push(&mut self, x: i32) {
|
||||
self.queue.push(x);
|
||||
}
|
||||
|
||||
fn pop(&mut self) -> i32 {
|
||||
let len = self.queue.len() - 1;
|
||||
for _ in 0..len {
|
||||
let tmp = self.queue.remove(0);
|
||||
self.queue.push(tmp);
|
||||
}
|
||||
self.queue.remove(0)
|
||||
}
|
||||
|
||||
fn top(&mut self) -> i32 {
|
||||
let res = self.pop();
|
||||
self.queue.push(res);
|
||||
res
|
||||
}
|
||||
|
||||
fn empty(&self) -> bool {
|
||||
self.queue.is_empty()
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
<p align="center">
|
||||
<a href="https://programmercarl.com/other/kstar.html" target="_blank">
|
||||
<img src="../pics/网站星球宣传海报.jpg" width="1000"/>
|
||||
|
@ -857,6 +857,36 @@ object Solution {
|
||||
}
|
||||
```
|
||||
|
||||
### rust
|
||||
|
||||
```rust
|
||||
impl Solution {
|
||||
//* 递归 */
|
||||
pub fn invert_tree(root: Option<Rc<RefCell<TreeNode>>>) -> Option<Rc<RefCell<TreeNode>>> {
|
||||
if let Some(node) = root.as_ref() {
|
||||
let (left, right) = (node.borrow().left.clone(), node.borrow().right.clone());
|
||||
node.borrow_mut().left = Self::invert_tree(right);
|
||||
node.borrow_mut().right = Self::invert_tree(left);
|
||||
}
|
||||
root
|
||||
}
|
||||
//* 迭代 */
|
||||
pub fn invert_tree(root: Option<Rc<RefCell<TreeNode>>>) -> Option<Rc<RefCell<TreeNode>>> {
|
||||
let mut stack = vec![root.clone()];
|
||||
while !stack.is_empty() {
|
||||
if let Some(node) = stack.pop().unwrap() {
|
||||
let (left, right) = (node.borrow().left.clone(), node.borrow().right.clone());
|
||||
stack.push(right.clone());
|
||||
stack.push(left.clone());
|
||||
node.borrow_mut().left = right;
|
||||
node.borrow_mut().right = left;
|
||||
}
|
||||
}
|
||||
root
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
<p align="center">
|
||||
<a href="https://programmercarl.com/other/kstar.html" target="_blank">
|
||||
<img src="../pics/网站星球宣传海报.jpg" width="1000"/>
|
||||
|
@ -622,6 +622,47 @@ class MyQueue() {
|
||||
}
|
||||
```
|
||||
|
||||
rust:
|
||||
|
||||
```rust
|
||||
struct MyQueue {
|
||||
stack_in: Vec<i32>,
|
||||
stack_out: Vec<i32>,
|
||||
}
|
||||
impl MyQueue {
|
||||
fn new() -> Self {
|
||||
MyQueue {
|
||||
stack_in: Vec::new(),
|
||||
stack_out: Vec::new(),
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fn push(&mut self, x: i32) {
|
||||
self.stack_in.push(x);
|
||||
}
|
||||
|
||||
fn pop(&mut self) -> i32 {
|
||||
if self.stack_out.is_empty(){
|
||||
while !self.stack_in.is_empty() {
|
||||
self.stack_out.push(self.stack_in.pop().unwrap());
|
||||
}
|
||||
}
|
||||
self.stack_out.pop().unwrap()
|
||||
}
|
||||
|
||||
fn peek(&mut self) -> i32 {
|
||||
let res = self.pop();
|
||||
self.stack_out.push(res);
|
||||
res
|
||||
}
|
||||
|
||||
fn empty(&self) -> bool {
|
||||
self.stack_in.is_empty() && self.stack_out.is_empty()
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
<p align="center">
|
||||
<a href="https://programmercarl.com/other/kstar.html" target="_blank">
|
||||
<img src="../pics/网站星球宣传海报.jpg" width="1000"/>
|
||||
|
@ -802,6 +802,35 @@ class myDequeue{
|
||||
}
|
||||
```
|
||||
|
||||
rust:
|
||||
|
||||
```rust
|
||||
impl Solution {
|
||||
pub fn max_sliding_window(nums: Vec<i32>, k: i32) -> Vec<i32> {
|
||||
let mut res = vec![];
|
||||
let mut queue = VecDeque::with_capacity(k as usize);
|
||||
for (i, &v) in nums.iter().enumerate() {
|
||||
// 如果队列长度超过 k,那么需要移除队首过期元素
|
||||
if i - queue.front().unwrap_or(&0) == k as usize {
|
||||
queue.pop_front();
|
||||
}
|
||||
while let Some(&index) = queue.back() {
|
||||
if nums[index] >= v {
|
||||
break;
|
||||
}
|
||||
// 如果队列第一个元素比当前元素小,那么就把队列第一个元素弹出
|
||||
queue.pop_back();
|
||||
}
|
||||
queue.push_back(i);
|
||||
if i >= k as usize - 1 {
|
||||
res.push(nums[queue[0]]);
|
||||
}
|
||||
}
|
||||
res
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
<p align="center">
|
||||
<a href="https://programmercarl.com/other/kstar.html" target="_blank">
|
||||
<img src="../pics/网站星球宣传海报.jpg" width="1000"/>
|
||||
|
@ -101,7 +101,7 @@ class Solution {
|
||||
int[] record = new int[26];
|
||||
|
||||
for (int i = 0; i < s.length(); i++) {
|
||||
record[s.charAt(i) - 'a']++;
|
||||
record[s.charAt(i) - 'a']++; // 并不需要记住字符a的ASCII,只要求出一个相对数值就可以了
|
||||
}
|
||||
|
||||
for (int i = 0; i < t.length(); i++) {
|
||||
@ -109,11 +109,11 @@ class Solution {
|
||||
}
|
||||
|
||||
for (int count: record) {
|
||||
if (count != 0) {
|
||||
if (count != 0) { // record数组如果有的元素不为零0,说明字符串s和t 一定是谁多了字符或者谁少了字符。
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
return true; // record数组所有元素都为零0,说明字符串s和t是字母异位词
|
||||
}
|
||||
}
|
||||
```
|
||||
@ -123,12 +123,11 @@ Python:
|
||||
class Solution:
|
||||
def isAnagram(self, s: str, t: str) -> bool:
|
||||
record = [0] * 26
|
||||
for i in range(len(s)):
|
||||
for i in s:
|
||||
#并不需要记住字符a的ASCII,只要求出一个相对数值就可以了
|
||||
record[ord(s[i]) - ord("a")] += 1
|
||||
print(record)
|
||||
for i in range(len(t)):
|
||||
record[ord(t[i]) - ord("a")] -= 1
|
||||
record[ord(i) - ord("a")] += 1
|
||||
for i in t:
|
||||
record[ord(i) - ord("a")] -= 1
|
||||
for i in range(26):
|
||||
if record[i] != 0:
|
||||
#record数组如果有的元素不为零0,说明字符串s和t 一定是谁多了字符或者谁少了字符。
|
||||
@ -154,38 +153,23 @@ class Solution:
|
||||
|
||||
return s_dict == t_dict
|
||||
```
|
||||
Python写法三(没有使用数组作为哈希表,只是介绍Counter这种更方便的解题思路):
|
||||
|
||||
```python
|
||||
class Solution(object):
|
||||
def isAnagram(self, s: str, t: str) -> bool:
|
||||
from collections import Counter
|
||||
a_count = Counter(s)
|
||||
b_count = Counter(t)
|
||||
return a_count == b_count
|
||||
```
|
||||
|
||||
Go:
|
||||
|
||||
```go
|
||||
func isAnagram(s string, t string) bool {
|
||||
if len(s)!=len(t){
|
||||
return false
|
||||
}
|
||||
exists := make(map[byte]int)
|
||||
for i:=0;i<len(s);i++{
|
||||
if v,ok:=exists[s[i]];v>=0&&ok{
|
||||
exists[s[i]]=v+1
|
||||
}else{
|
||||
exists[s[i]]=1
|
||||
}
|
||||
}
|
||||
for i:=0;i<len(t);i++{
|
||||
if v,ok:=exists[t[i]];v>=1&&ok{
|
||||
exists[t[i]]=v-1
|
||||
}else{
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
```
|
||||
|
||||
Go写法二(没有使用slice作为哈希表,用数组来代替):
|
||||
|
||||
```go
|
||||
func isAnagram(s string, t string) bool {
|
||||
record := [26]int{}
|
||||
|
||||
for _, r := range s {
|
||||
record[r-rune('a')]++
|
||||
}
|
||||
@ -193,7 +177,7 @@ func isAnagram(s string, t string) bool {
|
||||
record[r-rune('a')]--
|
||||
}
|
||||
|
||||
return record == [26]int{}
|
||||
return record == [26]int{} // record数组如果有的元素不为零0,说明字符串s和t 一定是谁多了字符或者谁少了字符。
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -151,6 +151,23 @@ class Solution {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 第二种方法用temp来交换数值更多人容易理解些
|
||||
class Solution {
|
||||
public void reverseString(char[] s) {
|
||||
int l = 0;
|
||||
int r = s.length - 1;
|
||||
while(l < r){
|
||||
char temp = s[l];
|
||||
s[l] = s[r];
|
||||
s[r] = temp;
|
||||
l++;
|
||||
r--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
```
|
||||
|
||||
Python:
|
||||
@ -173,11 +190,11 @@ class Solution:
|
||||
|
||||
Go:
|
||||
```Go
|
||||
func reverseString(s []byte) {
|
||||
left:=0
|
||||
right:=len(s)-1
|
||||
for left<right{
|
||||
s[left],s[right]=s[right],s[left]
|
||||
func reverseString(s []byte) {
|
||||
left := 0
|
||||
right := len(s)-1
|
||||
for left < right {
|
||||
s[left], s[right] = s[right], s[left]
|
||||
left++
|
||||
right--
|
||||
}
|
||||
@ -335,3 +352,4 @@ object Solution {
|
||||
<a href="https://programmercarl.com/other/kstar.html" target="_blank">
|
||||
<img src="../pics/网站星球宣传海报.jpg" width="1000"/>
|
||||
</a>
|
||||
|
||||
|
@ -487,7 +487,34 @@ object Solution {
|
||||
.map(_._1)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
rust: 小根堆
|
||||
|
||||
```rust
|
||||
use std::cmp::Reverse;
|
||||
use std::collections::{BinaryHeap, HashMap};
|
||||
impl Solution {
|
||||
pub fn top_k_frequent(nums: Vec<i32>, k: i32) -> Vec<i32> {
|
||||
let mut hash = HashMap::new();
|
||||
let mut heap = BinaryHeap::with_capacity(k as usize);
|
||||
nums.into_iter().for_each(|k| {
|
||||
*hash.entry(k).or_insert(0) += 1;
|
||||
});
|
||||
|
||||
for (k, v) in hash {
|
||||
if heap.len() == heap.capacity() {
|
||||
if *heap.peek().unwrap() < (Reverse(v), k) {
|
||||
continue;
|
||||
} else {
|
||||
heap.pop();
|
||||
}
|
||||
}
|
||||
heap.push((Reverse(v), k));
|
||||
}
|
||||
heap.into_iter().map(|(_, k)| k).collect()
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
<p align="center">
|
||||
|
@ -147,32 +147,24 @@ Python3:
|
||||
```python
|
||||
class Solution:
|
||||
def intersection(self, nums1: List[int], nums2: List[int]) -> List[int]:
|
||||
return list(set(nums1) & set(nums2)) # 两个数组先变成集合,求交集后还原为数组
|
||||
val_dict = {}
|
||||
ans = []
|
||||
for num in nums1:
|
||||
val_dict[num] = 1
|
||||
|
||||
for num in nums2:
|
||||
if num in val_dict.keys() and val_dict[num] == 1:
|
||||
ans.append(num)
|
||||
val_dict[num] = 0
|
||||
|
||||
return ans
|
||||
```
|
||||
|
||||
|
||||
Go:
|
||||
```go
|
||||
func intersection(nums1 []int, nums2 []int) []int {
|
||||
m := make(map[int]int)
|
||||
for _, v := range nums1 {
|
||||
m[v] = 1
|
||||
}
|
||||
var res []int
|
||||
// 利用count>0,实现重复值只拿一次放入返回结果中
|
||||
for _, v := range nums2 {
|
||||
if count, ok := m[v]; ok && count > 0 {
|
||||
res = append(res, v)
|
||||
m[v]--
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
```
|
||||
```golang
|
||||
//优化版,利用set,减少count统计
|
||||
func intersection(nums1 []int, nums2 []int) []int {
|
||||
set:=make(map[int]struct{},0)
|
||||
set:=make(map[int]struct{},0) // 用map模拟set
|
||||
res:=make([]int,0)
|
||||
for _,v:=range nums1{
|
||||
if _,ok:=set[v];!ok{
|
||||
|
@ -264,6 +264,25 @@ class Solution:
|
||||
return max(dp[-1][0], dp[-1][1])
|
||||
```
|
||||
|
||||
```python
|
||||
class Solution:
|
||||
def wiggleMaxLength(self, nums: List[int]) -> int:
|
||||
# up i作为波峰最长的序列长度
|
||||
# down i作为波谷最长的序列长度
|
||||
n = len(nums)
|
||||
# 长度为0和1的直接返回长度
|
||||
if n<2: return n
|
||||
for i in range(1,n):
|
||||
if nums[i]>nums[i-1]:
|
||||
# nums[i] 为波峰,1. 前面是波峰,up值不变,2. 前面是波谷,down值加1
|
||||
# 目前up值取两者的较大值(其实down+1即可,可以推理前一步down和up最多相差1,所以down+1>=up)
|
||||
up = max(up, down+1)
|
||||
elif nums[i]<nums[i-1]:
|
||||
# nums[i] 为波谷,1. 前面是波峰,up+1,2. 前面是波谷,down不变,取较大值
|
||||
down = max(down, up+1)
|
||||
return max(up, down)
|
||||
```
|
||||
|
||||
### Go
|
||||
|
||||
**贪心**
|
||||
|
@ -147,11 +147,11 @@ class Solution:
|
||||
|
||||
arr = [0] * 26
|
||||
|
||||
for x in magazine:
|
||||
for x in magazine: # 记录 magazine里各个字符出现次数
|
||||
arr[ord(x) - ord('a')] += 1
|
||||
|
||||
for x in ransomNote:
|
||||
if arr[ord(x) - ord('a')] == 0:
|
||||
for x in ransomNote: # 在arr里对应的字符个数做--操作
|
||||
if arr[ord(x) - ord('a')] == 0: # 如果没有出现过直接返回
|
||||
return False
|
||||
else:
|
||||
arr[ord(x) - ord('a')] -= 1
|
||||
@ -234,12 +234,12 @@ Go:
|
||||
```go
|
||||
func canConstruct(ransomNote string, magazine string) bool {
|
||||
record := make([]int, 26)
|
||||
for _, v := range magazine {
|
||||
for _, v := range magazine { // 通过recode数据记录 magazine里各个字符出现次数
|
||||
record[v-'a']++
|
||||
}
|
||||
for _, v := range ransomNote {
|
||||
for _, v := range ransomNote { // 遍历ransomNote,在record里对应的字符个数做--操作
|
||||
record[v-'a']--
|
||||
if record[v-'a'] < 0 {
|
||||
if record[v-'a'] < 0 { // 如果小于零说明ransomNote里出现的字符,magazine没有
|
||||
return false
|
||||
}
|
||||
}
|
||||
@ -258,12 +258,12 @@ javaScript:
|
||||
var canConstruct = function(ransomNote, magazine) {
|
||||
const strArr = new Array(26).fill(0),
|
||||
base = "a".charCodeAt();
|
||||
for(const s of magazine) {
|
||||
for(const s of magazine) { // 记录 magazine里各个字符出现次数
|
||||
strArr[s.charCodeAt() - base]++;
|
||||
}
|
||||
for(const s of ransomNote) {
|
||||
for(const s of ransomNote) { // 对应的字符个数做--操作
|
||||
const index = s.charCodeAt() - base;
|
||||
if(!strArr[index]) return false;
|
||||
if(!strArr[index]) return false; // 如果没记录过直接返回false
|
||||
strArr[index]--;
|
||||
}
|
||||
return true;
|
||||
|
@ -168,13 +168,15 @@ Go:
|
||||
|
||||
```go
|
||||
func fourSumCount(nums1 []int, nums2 []int, nums3 []int, nums4 []int) int {
|
||||
m := make(map[int]int)
|
||||
m := make(map[int]int) //key:a+b的数值,value:a+b数值出现的次数
|
||||
count := 0
|
||||
for _, v1 := range nums1 {
|
||||
// 遍历nums1和nums2数组,统计两个数组元素之和,和出现的次数,放到map中
|
||||
for _, v1 := range nums1 {
|
||||
for _, v2 := range nums2 {
|
||||
m[v1+v2]++
|
||||
}
|
||||
}
|
||||
// 遍历nums3和nums4数组,找到如果 0-(c+d) 在map中出现过的话,就把map中key对应的value也就是出现次数统计出来
|
||||
for _, v3 := range nums3 {
|
||||
for _, v4 := range nums4 {
|
||||
count += m[-v3-v4]
|
||||
@ -197,14 +199,14 @@ javaScript:
|
||||
var fourSumCount = function(nums1, nums2, nums3, nums4) {
|
||||
const twoSumMap = new Map();
|
||||
let count = 0;
|
||||
|
||||
// 统计nums1和nums2数组元素之和,和出现的次数,放到map中
|
||||
for(const n1 of nums1) {
|
||||
for(const n2 of nums2) {
|
||||
const sum = n1 + n2;
|
||||
twoSumMap.set(sum, (twoSumMap.get(sum) || 0) + 1)
|
||||
}
|
||||
}
|
||||
|
||||
// 找到如果 0-(c+d) 在map中出现过的话,就把map中key对应的value也就是出现次数统计出来
|
||||
for(const n3 of nums3) {
|
||||
for(const n4 of nums4) {
|
||||
const sum = n3 + n4;
|
||||
|
@ -46,17 +46,17 @@
|
||||
|
||||
## 移动匹配
|
||||
|
||||
当一个字符串s:abcabc,内部又重复的子串组成,那么这个字符串的结构一定是这样的:
|
||||
当一个字符串s:abcabc,内部由重复的子串组成,那么这个字符串的结构一定是这样的:
|
||||
|
||||

|
||||
|
||||
也就是又前后又相同的子串组成。
|
||||
也就是由前后相同的子串组成。
|
||||
|
||||
那么既然前面有相同的子串,后面有相同的子串,用 s + s,这样组成的字符串中,后面的子串做前串,前后的子串做后串,就一定还能组成一个s,如图:
|
||||
|
||||

|
||||
|
||||
所以判断字符串s是否有重复子串组成,只要两个s拼接在一起,里面还出现一个s的话,就说明是又重复子串组成。
|
||||
所以判断字符串s是否由重复子串组成,只要两个s拼接在一起,里面还出现一个s的话,就说明是由重复子串组成。
|
||||
|
||||
当然,我们在判断 s + s 拼接的字符串里是否出现一个s的的时候,**要刨除 s + s 的首字符和尾字符**,这样避免在s+s中搜索出原来的s,我们要搜索的是中间拼接出来的s。
|
||||
|
||||
@ -81,7 +81,7 @@ public:
|
||||
## KMP
|
||||
|
||||
### 为什么会使用KMP
|
||||
以下使用KMP方式讲解,强烈建议大家先把一下两个视频看了,理解KMP算法,在来看下面讲解,否则会很懵。
|
||||
以下使用KMP方式讲解,强烈建议大家先把以下两个视频看了,理解KMP算法,再来看下面讲解,否则会很懵。
|
||||
|
||||
* [视频讲解版:帮你把KMP算法学个通透!(理论篇)](https://www.bilibili.com/video/BV1PD4y1o7nd/)
|
||||
* [视频讲解版:帮你把KMP算法学个通透!(求next数组代码篇)](https://www.bilibili.com/video/BV1M5411j7Xx)
|
||||
@ -93,12 +93,12 @@ KMP算法中next数组为什么遇到字符不匹配的时候可以找到上一
|
||||
|
||||
那么 最长相同前后缀和重复子串的关系又有什么关系呢。
|
||||
|
||||
可能很多录友又忘了 前缀和后缀的定义,在回顾一下:
|
||||
可能很多录友又忘了 前缀和后缀的定义,再回顾一下:
|
||||
|
||||
* 前缀是指不包含最后一个字符的所有以第一个字符开头的连续子串;
|
||||
* 后缀是指不包含第一个字符的所有以最后一个字符结尾的连续子串
|
||||
|
||||
在由重复子串组成的字符串中,最长相等前后缀不包含的子串就是最小重复子串,这里那字符串s:abababab 来举例,ab就是最小重复单位,如图所示:
|
||||
在由重复子串组成的字符串中,最长相等前后缀不包含的子串就是最小重复子串,这里拿字符串s:abababab 来举例,ab就是最小重复单位,如图所示:
|
||||
|
||||

|
||||
|
||||
@ -123,11 +123,11 @@ KMP算法中next数组为什么遇到字符不匹配的时候可以找到上一
|
||||
|
||||
### 简单推理
|
||||
|
||||
这里在给出一个数推导,就容易理解很多。
|
||||
这里再给出一个数学推导,就容易理解很多。
|
||||
|
||||
假设字符串s使用多个重复子串构成(这个子串是最小重复单位),重复出现的子字符串长度是x,所以s是由n * x组成。
|
||||
|
||||
因为字符串s的最长相同前后缀的的长度一定是不包含s本身,所以 最长相同前后缀长度必然是m * x,而且 n - m = 1,(这里如果不懂,看上面的推理)
|
||||
因为字符串s的最长相同前后缀的长度一定是不包含s本身,所以 最长相同前后缀长度必然是m * x,而且 n - m = 1,(这里如果不懂,看上面的推理)
|
||||
|
||||
所以如果 nx % (n - m)x = 0,就可以判定有重复出现的子字符串。
|
||||
|
||||
|
@ -194,6 +194,29 @@ class Solution {
|
||||
return new String(ch);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 解法二还可以用temp来交换数值,会的人更多些
|
||||
class Solution {
|
||||
public String reverseStr(String s, int k) {
|
||||
char[] ch = s.toCharArray();
|
||||
for(int i = 0;i < ch.length;i += 2 * k){
|
||||
int start = i;
|
||||
// 判断尾数够不够k个来取决end指针的位置
|
||||
int end = Math.min(ch.length - 1,start + k - 1);
|
||||
while(start < end){
|
||||
|
||||
char temp = ch[start];
|
||||
ch[start] = ch[end];
|
||||
ch[end] = temp;
|
||||
|
||||
start++;
|
||||
end--;
|
||||
}
|
||||
}
|
||||
return new String(ch);
|
||||
}
|
||||
}
|
||||
```
|
||||
```java
|
||||
// 解法3
|
||||
@ -271,6 +294,8 @@ func reverseStr(s string, k int) string {
|
||||
ss := []byte(s)
|
||||
length := len(s)
|
||||
for i := 0; i < length; i += 2 * k {
|
||||
// 1. 每隔 2k 个字符的前 k 个字符进行反转
|
||||
// 2. 剩余字符小于 2k 但大于或等于 k 个,则反转前 k 个字符
|
||||
if i + k <= length {
|
||||
reverse(ss[i:i+k])
|
||||
} else {
|
||||
@ -303,7 +328,7 @@ javaScript:
|
||||
var reverseStr = function(s, k) {
|
||||
const len = s.length;
|
||||
let resArr = s.split("");
|
||||
for(let i = 0; i < len; i += 2 * k) {
|
||||
for(let i = 0; i < len; i += 2 * k) { // 每隔 2k 个字符的前 k 个字符进行反转
|
||||
let l = i - 1, r = i + k > len ? len : i + k;
|
||||
while(++l < --r) [resArr[l], resArr[r]] = [resArr[r], resArr[l]];
|
||||
}
|
||||
@ -469,3 +494,4 @@ impl Solution {
|
||||
<a href="https://programmercarl.com/other/kstar.html" target="_blank">
|
||||
<img src="../pics/网站星球宣传海报.jpg" width="1000"/>
|
||||
</a>
|
||||
|
||||
|
@ -228,28 +228,43 @@ func min(a, b int) int {
|
||||
```
|
||||
Javascript:
|
||||
```javascript
|
||||
const minDistance = (word1, word2) => {
|
||||
let dp = Array.from(new Array(word1.length + 1), () => Array(word2.length+1).fill(0));
|
||||
|
||||
for(let i = 1; i <= word1.length; i++) {
|
||||
dp[i][0] = i;
|
||||
// 方法一
|
||||
var minDistance = (word1, word2) => {
|
||||
let dp = Array.from(new Array(word1.length + 1), () =>
|
||||
Array(word2.length + 1).fill(0)
|
||||
);
|
||||
for (let i = 1; i <= word1.length; i++) {
|
||||
dp[i][0] = i;
|
||||
}
|
||||
for (let j = 1; j <= word2.length; j++) {
|
||||
dp[0][j] = j;
|
||||
}
|
||||
for (let i = 1; i <= word1.length; i++) {
|
||||
for (let j = 1; j <= word2.length; j++) {
|
||||
if (word1[i - 1] === word2[j - 1]) {
|
||||
dp[i][j] = dp[i - 1][j - 1];
|
||||
} else {
|
||||
dp[i][j] = Math.min(
|
||||
dp[i - 1][j] + 1,
|
||||
dp[i][j - 1] + 1,
|
||||
dp[i - 1][j - 1] + 2
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
return dp[word1.length][word2.length];
|
||||
};
|
||||
|
||||
for(let j = 1; j <= word2.length; j++) {
|
||||
dp[0][j] = j;
|
||||
}
|
||||
|
||||
for(let i = 1; i <= word1.length; i++) {
|
||||
for(let j = 1; j <= word2.length; j++) {
|
||||
if(word1[i-1] === word2[j-1]) {
|
||||
dp[i][j] = dp[i-1][j-1];
|
||||
} else {
|
||||
dp[i][j] = Math.min(dp[i-1][j] + 1, dp[i][j-1] + 1, dp[i-1][j-1] + 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return dp[word1.length][word2.length];
|
||||
// 方法二
|
||||
var minDistance = function (word1, word2) {
|
||||
let dp = new Array(word1.length + 1)
|
||||
.fill(0)
|
||||
.map((_) => new Array(word2.length + 1).fill(0));
|
||||
for (let i = 1; i <= word1.length; i++)
|
||||
for (let j = 1; j <= word2.length; j++)
|
||||
if (word1[i - 1] === word2[j - 1]) dp[i][j] = dp[i - 1][j - 1] + 1;
|
||||
else dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);
|
||||
return word1.length + word2.length - dp[word1.length][word2.length] * 2;
|
||||
};
|
||||
```
|
||||
|
||||
|
@ -108,9 +108,12 @@ public:
|
||||
// 如果index大于链表的长度,则返回空
|
||||
// 如果index小于0,则置为0,作为链表的新头节点。
|
||||
void addAtIndex(int index, int val) {
|
||||
if (index > _size || index < 0) {
|
||||
if (index > _size) {
|
||||
return;
|
||||
}
|
||||
if (index < 0) {
|
||||
index = 0;
|
||||
}
|
||||
LinkedNode* newNode = new LinkedNode(val);
|
||||
LinkedNode* cur = _dummyHead;
|
||||
while(index--) {
|
||||
@ -302,7 +305,7 @@ class MyLinkedList {
|
||||
head = new ListNode(0);
|
||||
}
|
||||
|
||||
//获取第index个节点的数值
|
||||
//获取第index个节点的数值,注意index是从0开始的,第0个节点就是头结点
|
||||
public int get(int index) {
|
||||
//如果index非法,返回-1
|
||||
if (index < 0 || index >= size) {
|
||||
@ -316,12 +319,12 @@ class MyLinkedList {
|
||||
return currentNode.val;
|
||||
}
|
||||
|
||||
//在链表最前面插入一个节点
|
||||
//在链表最前面插入一个节点,等价于在第0个元素前添加
|
||||
public void addAtHead(int val) {
|
||||
addAtIndex(0, val);
|
||||
}
|
||||
|
||||
//在链表的最后插入一个节点
|
||||
//在链表的最后插入一个节点,等价于在(末尾+1)个元素前添加
|
||||
public void addAtTail(int val) {
|
||||
addAtIndex(size, val);
|
||||
}
|
||||
@ -478,76 +481,90 @@ class MyLinkedList {
|
||||
Python:
|
||||
```python
|
||||
# 单链表
|
||||
class Node:
|
||||
|
||||
def __init__(self, val):
|
||||
self.val = val
|
||||
class Node(object):
|
||||
def __init__(self, x=0):
|
||||
self.val = x
|
||||
self.next = None
|
||||
|
||||
|
||||
class MyLinkedList:
|
||||
class MyLinkedList(object):
|
||||
|
||||
def __init__(self):
|
||||
self._head = Node(0) # 虚拟头部节点
|
||||
self._count = 0 # 添加的节点数
|
||||
self.head = Node()
|
||||
self.size = 0 # 设置一个链表长度的属性,便于后续操作,注意每次增和删的时候都要更新
|
||||
|
||||
def get(self, index: int) -> int:
|
||||
def get(self, index):
|
||||
"""
|
||||
Get the value of the index-th node in the linked list. If the index is invalid, return -1.
|
||||
:type index: int
|
||||
:rtype: int
|
||||
"""
|
||||
if 0 <= index < self._count:
|
||||
node = self._head
|
||||
for _ in range(index + 1):
|
||||
node = node.next
|
||||
return node.val
|
||||
else:
|
||||
if index < 0 or index >= self.size:
|
||||
return -1
|
||||
cur = self.head.next
|
||||
while(index):
|
||||
cur = cur.next
|
||||
index -= 1
|
||||
return cur.val
|
||||
|
||||
def addAtHead(self, val: int) -> None:
|
||||
def addAtHead(self, val):
|
||||
"""
|
||||
Add a node of value val before the first element of the linked list. After the insertion, the new node will be the first node of the linked list.
|
||||
:type val: int
|
||||
:rtype: None
|
||||
"""
|
||||
self.addAtIndex(0, val)
|
||||
new_node = Node(val)
|
||||
new_node.next = self.head.next
|
||||
self.head.next = new_node
|
||||
self.size += 1
|
||||
|
||||
def addAtTail(self, val: int) -> None:
|
||||
def addAtTail(self, val):
|
||||
"""
|
||||
Append a node of value val to the last element of the linked list.
|
||||
:type val: int
|
||||
:rtype: None
|
||||
"""
|
||||
self.addAtIndex(self._count, val)
|
||||
new_node = Node(val)
|
||||
cur = self.head
|
||||
while(cur.next):
|
||||
cur = cur.next
|
||||
cur.next = new_node
|
||||
self.size += 1
|
||||
|
||||
def addAtIndex(self, index: int, val: int) -> None:
|
||||
def addAtIndex(self, index, val):
|
||||
"""
|
||||
Add a node of value val before the index-th node in the linked list. If index equals to the length of linked list, the node will be appended to the end of linked list. If index is greater than the length, the node will not be inserted.
|
||||
:type index: int
|
||||
:type val: int
|
||||
:rtype: None
|
||||
"""
|
||||
if index < 0:
|
||||
index = 0
|
||||
elif index > self._count:
|
||||
self.addAtHead(val)
|
||||
return
|
||||
elif index == self.size:
|
||||
self.addAtTail(val)
|
||||
return
|
||||
elif index > self.size:
|
||||
return
|
||||
|
||||
# 计数累加
|
||||
self._count += 1
|
||||
|
||||
add_node = Node(val)
|
||||
prev_node, current_node = None, self._head
|
||||
for _ in range(index + 1):
|
||||
prev_node, current_node = current_node, current_node.next
|
||||
else:
|
||||
prev_node.next, add_node.next = add_node, current_node
|
||||
|
||||
def deleteAtIndex(self, index: int) -> None:
|
||||
node = Node(val)
|
||||
pre = self.head
|
||||
while(index):
|
||||
pre = pre.next
|
||||
index -= 1
|
||||
node.next = pre.next
|
||||
pre.next = node
|
||||
self.size += 1
|
||||
|
||||
def deleteAtIndex(self, index):
|
||||
"""
|
||||
Delete the index-th node in the linked list, if the index is valid.
|
||||
:type index: int
|
||||
:rtype: None
|
||||
"""
|
||||
if 0 <= index < self._count:
|
||||
# 计数-1
|
||||
self._count -= 1
|
||||
prev_node, current_node = None, self._head
|
||||
for _ in range(index + 1):
|
||||
prev_node, current_node = current_node, current_node.next
|
||||
else:
|
||||
prev_node.next, current_node.next = current_node.next, None
|
||||
|
||||
|
||||
if index < 0 or index >= self.size:
|
||||
return
|
||||
pre = self.head
|
||||
while(index):
|
||||
pre = pre.next
|
||||
index -= 1
|
||||
pre.next = pre.next.next
|
||||
self.size -= 1
|
||||
|
||||
# 双链表
|
||||
# 相对于单链表, Node新增了prev属性
|
||||
class Node:
|
||||
|
@ -206,13 +206,13 @@ class Solution: # 贪心思路
|
||||
result = 0
|
||||
minPrice = prices[0]
|
||||
for i in range(1, len(prices)):
|
||||
if prices[i] < minPrice:
|
||||
if prices[i] < minPrice: # 此时有更低的价格,可以买入
|
||||
minPrice = prices[i]
|
||||
elif prices[i] >= minPrice and prices[i] <= minPrice + fee:
|
||||
continue
|
||||
else:
|
||||
result += prices[i] - minPrice - fee
|
||||
elif prices[i] > (minPrice + fee): # 此时有利润,同时假买入高价的股票,看看是否继续盈利
|
||||
result += prices[i] - (minPrice + fee)
|
||||
minPrice = prices[i] - fee
|
||||
else: # minPrice<= prices[i] <= minPrice + fee, 价格处于minPrice和minPrice+fee之间,不做操作
|
||||
continue
|
||||
return result
|
||||
```
|
||||
|
||||
|
@ -387,6 +387,34 @@ var canVisitAllRooms = function(rooms) {
|
||||
```
|
||||
|
||||
|
||||
### TypeScript
|
||||
```ts
|
||||
// BFS
|
||||
// rooms :就是一个链接表 表示的有向图
|
||||
// 转换问题就是,一次遍历从 0开始 能不能 把所有的节点访问了,实质问题就是一个
|
||||
// 层序遍历
|
||||
function canVisitAllRooms(rooms: number[][]): boolean {
|
||||
const n = rooms.length;
|
||||
// cnt[i] 代表节点 i 的访问顺序, cnt[i] = 0, 代表没被访问过
|
||||
let cnt = new Array(n).fill(0);
|
||||
let queue = [0];
|
||||
cnt[0]++;
|
||||
while (queue.length > 0) {
|
||||
const from = queue.shift();
|
||||
for (let i = 0; i < rooms[from].length; i++) {
|
||||
const to = rooms[from][i];
|
||||
if (cnt[to] == 0) {
|
||||
queue.push(to);
|
||||
cnt[to]++;
|
||||
}
|
||||
}
|
||||
}
|
||||
// 只要其中有一个节点 没被访问过,那么就返回 false
|
||||
return cnt.every((item) => item != 0);
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
<p align="center">
|
||||
<a href="https://programmercarl.com/other/kstar.html" target="_blank">
|
||||
<img src="../pics/网站星球宣传海报.jpg" width="1000"/>
|
||||
|
@ -447,6 +447,25 @@ object Solution {
|
||||
}
|
||||
```
|
||||
|
||||
rust:
|
||||
|
||||
```rust
|
||||
impl Solution {
|
||||
pub fn remove_duplicates(s: String) -> String {
|
||||
let mut stack = vec![];
|
||||
let mut chars: Vec<char> = s.chars().collect();
|
||||
while let Some(c) = chars.pop() {
|
||||
if stack.is_empty() || stack[stack.len() - 1] != c {
|
||||
stack.push(c);
|
||||
} else {
|
||||
stack.pop();
|
||||
}
|
||||
}
|
||||
stack.into_iter().rev().collect()
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
<p align="center">
|
||||
<a href="https://programmercarl.com/other/kstar.html" target="_blank">
|
||||
<img src="../pics/网站星球宣传海报.jpg" width="1000"/>
|
||||
|
@ -76,8 +76,67 @@ public:
|
||||
return count;
|
||||
}
|
||||
};
|
||||
```
|
||||
## 其他语言版本
|
||||
|
||||
### JavaScript:
|
||||
|
||||
```js
|
||||
/**
|
||||
* @param {number[][]} grid
|
||||
* @return {number}
|
||||
*/
|
||||
var closedIsland = function(grid) {
|
||||
let rows = grid.length;
|
||||
let cols = grid[0].length;
|
||||
// 存储四个方向
|
||||
let dir = [[-1, 0], [0, -1], [1, 0], [0, 1]];
|
||||
// 深度优先
|
||||
function dfs(x, y) {
|
||||
grid[x][y] = 1;
|
||||
// 向四个方向遍历
|
||||
for(let i = 0; i < 4; i++) {
|
||||
let nextX = x + dir[i][0];
|
||||
let nextY = y + dir[i][1];
|
||||
// 判断是否越界
|
||||
if (nextX < 0 || nextX >= rows || nextY < 0 || nextY >= cols) continue;
|
||||
// 不符合条件
|
||||
if (grid[nextX][nextY] === 1) continue;
|
||||
// 继续递归
|
||||
dfs(nextX, nextY);
|
||||
}
|
||||
}
|
||||
// 从边界岛屿开始
|
||||
// 从左侧和右侧出发
|
||||
for(let i = 0; i < rows; i++) {
|
||||
if (grid[i][0] === 0) dfs(i, 0);
|
||||
if (grid[i][cols - 1] === 0) dfs(i, cols - 1);
|
||||
}
|
||||
// 从上侧和下侧出发
|
||||
for(let j = 0; j < cols; j++) {
|
||||
if (grid[0][j] === 0) dfs(0, j);
|
||||
if (grid[rows - 1][j] === 0) dfs(rows - 1, j);
|
||||
}
|
||||
let count = 0;
|
||||
// 排除所有与边界相连的陆地之后
|
||||
// 依次遍历网格中的每个元素,如果遇到一个元素是陆地且状态是未访问,则遇到一个新的岛屿,将封闭岛屿的数目加 1
|
||||
// 并访问与当前陆地连接的所有陆地
|
||||
for(let i = 0; i < rows; i++) {
|
||||
for(let j = 0; j < cols; j++) {
|
||||
if (grid[i][j] === 0) {
|
||||
count++;
|
||||
dfs(i, j);
|
||||
}
|
||||
}
|
||||
}
|
||||
return count;
|
||||
};
|
||||
```
|
||||
|
||||
|
||||
<p align="center">
|
||||
<a href="https://programmercarl.com/other/kstar.html" target="_blank">
|
||||
<img src="../pics/网站星球宣传海报.jpg" width="1000"/>
|
||||
</a>
|
||||
|
||||
|
||||
|
@ -270,6 +270,29 @@ class TreeNode(_value: Int = 0, _left: TreeNode = null, _right: TreeNode = null)
|
||||
var right: TreeNode = _right
|
||||
}
|
||||
```
|
||||
|
||||
rust:
|
||||
|
||||
```rust
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub struct TreeNode<T> {
|
||||
pub val: T,
|
||||
pub left: Option<Rc<RefCell<TreeNode<T>>>>,
|
||||
pub right: Option<Rc<RefCell<TreeNode<T>>>>,
|
||||
}
|
||||
|
||||
impl<T> TreeNode<T> {
|
||||
#[inline]
|
||||
pub fn new(val: T) -> Self {
|
||||
TreeNode {
|
||||
val,
|
||||
left: None,
|
||||
right: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
<p align="center">
|
||||
<a href="https://programmercarl.com/other/kstar.html" target="_blank">
|
||||
<img src="../pics/网站星球宣传海报.jpg" width="1000"/>
|
||||
|
@ -666,6 +666,83 @@ object Solution {
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
rust:
|
||||
|
||||
```rust
|
||||
impl Solution{
|
||||
// 前序
|
||||
pub fn preorder_traversal(root: Option<Rc<RefCell<TreeNode>>>) -> Vec<i32> {
|
||||
let mut res = vec![];
|
||||
let mut stack = vec![];
|
||||
if root.is_some(){
|
||||
stack.push(root);
|
||||
}
|
||||
while !stack.is_empty(){
|
||||
if let Some(node) = stack.pop().unwrap(){
|
||||
if node.borrow().right.is_some(){
|
||||
stack.push(node.borrow().right.clone());
|
||||
}
|
||||
if node.borrow().left.is_some(){
|
||||
stack.push(node.borrow().left.clone());
|
||||
}
|
||||
stack.push(Some(node));
|
||||
stack.push(None);
|
||||
}else{
|
||||
res.push(stack.pop().unwrap().unwrap().borrow().val);
|
||||
}
|
||||
}
|
||||
res
|
||||
}
|
||||
// 中序
|
||||
pub fn inorder_traversal(root: Option<Rc<RefCell<TreeNode>>>) -> Vec<i32> {
|
||||
let mut res = vec![];
|
||||
let mut stack = vec![];
|
||||
if root.is_some() {
|
||||
stack.push(root);
|
||||
}
|
||||
while !stack.is_empty() {
|
||||
if let Some(node) = stack.pop().unwrap() {
|
||||
if node.borrow().right.is_some() {
|
||||
stack.push(node.borrow().right.clone());
|
||||
}
|
||||
stack.push(Some(node.clone()));
|
||||
stack.push(None);
|
||||
if node.borrow().left.is_some() {
|
||||
stack.push(node.borrow().left.clone());
|
||||
}
|
||||
} else {
|
||||
res.push(stack.pop().unwrap().unwrap().borrow().val);
|
||||
}
|
||||
}
|
||||
res
|
||||
}
|
||||
// 后序
|
||||
pub fn postorder_traversal(root: Option<Rc<RefCell<TreeNode>>>) -> Vec<i32> {
|
||||
let mut res = vec![];
|
||||
let mut stack = vec![];
|
||||
if root.is_some() {
|
||||
stack.push(root);
|
||||
}
|
||||
while !stack.is_empty() {
|
||||
if let Some(node) = stack.pop().unwrap() {
|
||||
stack.push(Some(node.clone()));
|
||||
stack.push(None);
|
||||
if node.borrow().right.is_some() {
|
||||
stack.push(node.borrow().right.clone());
|
||||
}
|
||||
if node.borrow().left.is_some() {
|
||||
stack.push(node.borrow().left.clone());
|
||||
}
|
||||
} else {
|
||||
res.push(stack.pop().unwrap().unwrap().borrow().val);
|
||||
}
|
||||
}
|
||||
res
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
<p align="center">
|
||||
<a href="https://programmercarl.com/other/kstar.html" target="_blank">
|
||||
<img src="../pics/网站星球宣传海报.jpg" width="1000"/>
|
||||
|
@ -640,6 +640,60 @@ object Solution {
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
rust:
|
||||
|
||||
```rust
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
impl Solution {
|
||||
//前序
|
||||
pub fn preorder_traversal(root: Option<Rc<RefCell<TreeNode>>>) -> Vec<i32> {
|
||||
let mut res = vec![];
|
||||
let mut stack = vec![root];
|
||||
while !stack.is_empty() {
|
||||
if let Some(node) = stack.pop().unwrap() {
|
||||
res.push(node.borrow().val);
|
||||
stack.push(node.borrow().right.clone());
|
||||
stack.push(node.borrow().left.clone());
|
||||
}
|
||||
}
|
||||
res
|
||||
}
|
||||
//中序
|
||||
pub fn inorder_traversal(root: Option<Rc<RefCell<TreeNode>>>) -> Vec<i32> {
|
||||
let mut res = vec![];
|
||||
let mut stack = vec![];
|
||||
let mut node = root;
|
||||
|
||||
while !stack.is_empty() || node.is_some() {
|
||||
while let Some(n) = node {
|
||||
node = n.borrow().left.clone();
|
||||
stack.push(n);
|
||||
}
|
||||
if let Some(n) = stack.pop() {
|
||||
res.push(n.borrow().val);
|
||||
node = n.borrow().right.clone();
|
||||
}
|
||||
}
|
||||
res
|
||||
}
|
||||
//后序
|
||||
pub fn postorder_traversal(root: Option<Rc<RefCell<TreeNode>>>) -> Vec<i32> {
|
||||
let mut res = vec![];
|
||||
let mut stack = vec![root];
|
||||
while !stack.is_empty() {
|
||||
if let Some(node) = stack.pop().unwrap() {
|
||||
res.push(node.borrow().val);
|
||||
stack.push(node.borrow().left.clone());
|
||||
stack.push(node.borrow().right.clone());
|
||||
}
|
||||
}
|
||||
res.into_iter().rev().collect()
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
<p align="center">
|
||||
<a href="https://programmercarl.com/other/kstar.html" target="_blank">
|
||||
<img src="../pics/网站星球宣传海报.jpg" width="1000"/>
|
||||
|
@ -525,6 +525,46 @@ object Solution {
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
rust:
|
||||
|
||||
```rust
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
impl Solution {
|
||||
pub fn preorder_traversal(root: Option<Rc<RefCell<TreeNode>>>) -> Vec<i32> {
|
||||
let mut res = vec![];
|
||||
Self::traverse(&root, &mut res);
|
||||
res
|
||||
}
|
||||
|
||||
//前序遍历
|
||||
pub fn traverse(root: &Option<Rc<RefCell<TreeNode>>>, res: &mut Vec<i32>) {
|
||||
if let Some(node) = root {
|
||||
res.push(node.borrow().val);
|
||||
Self::traverse(&node.borrow().left, res);
|
||||
Self::traverse(&node.borrow().right, res);
|
||||
}
|
||||
}
|
||||
//后序遍历
|
||||
pub fn traverse(root: &Option<Rc<RefCell<TreeNode>>>, res: &mut Vec<i32>) {
|
||||
if let Some(node) = root {
|
||||
Self::traverse(&node.borrow().left, res);
|
||||
Self::traverse(&node.borrow().right, res);
|
||||
res.push(node.borrow().val);
|
||||
}
|
||||
}
|
||||
//中序遍历
|
||||
pub fn traverse(root: &Option<Rc<RefCell<TreeNode>>>, res: &mut Vec<i32>) {
|
||||
if let Some(node) = root {
|
||||
Self::traverse(&node.borrow().left, res);
|
||||
res.push(node.borrow().val);
|
||||
Self::traverse(&node.borrow().right, res);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
<p align="center">
|
||||
<a href="https://programmercarl.com/other/kstar.html" target="_blank">
|
||||
<img src="../pics/网站星球宣传海报.jpg" width="1000"/>
|
||||
|
@ -36,7 +36,7 @@ i指向新长度的末尾,j指向旧长度的末尾。
|
||||
这么做有两个好处:
|
||||
|
||||
1. 不用申请新数组。
|
||||
2. 从后向前填充元素,避免了从前先后填充元素要来的 每次添加元素都要将添加元素之后的所有元素向后移动。
|
||||
2. 从后向前填充元素,避免了从前向后填充元素时,每次添加元素都要将添加元素之后的所有元素向后移动的问题。
|
||||
|
||||
时间复杂度,空间复杂度均超过100%的用户。
|
||||
|
||||
|
@ -31,7 +31,7 @@
|
||||
不能使用额外空间的话,模拟在本串操作要实现左旋转字符串的功能还是有点困难的。
|
||||
|
||||
|
||||
那么我们可以想一下上一题目[字符串:花式反转还不够!](https://programmercarl.com/0151.翻转字符串里的单词.html)中讲过,使用整体反转+局部反转就可以实现,反转单词顺序的目的。
|
||||
那么我们可以想一下上一题目[字符串:花式反转还不够!](https://programmercarl.com/0151.翻转字符串里的单词.html)中讲过,使用整体反转+局部反转就可以实现反转单词顺序的目的。
|
||||
|
||||
这道题目也非常类似,依然可以通过局部反转+整体反转 达到左旋转的目的。
|
||||
|
||||
@ -41,7 +41,7 @@
|
||||
2. 反转区间为n到末尾的子串
|
||||
3. 反转整个字符串
|
||||
|
||||
最后就可以得到左旋n的目的,而不用定义新的字符串,完全在本串上操作。
|
||||
最后就可以达到左旋n的目的,而不用定义新的字符串,完全在本串上操作。
|
||||
|
||||
例如 :示例1中 输入:字符串abcdefg,n=2
|
||||
|
||||
@ -75,7 +75,7 @@ public:
|
||||
|
||||
在这篇文章[344.反转字符串](https://programmercarl.com/0344.反转字符串.html),第一次讲到反转一个字符串应该怎么做,使用了双指针法。
|
||||
|
||||
然后发现[541. 反转字符串II](https://programmercarl.com/0541.反转字符串II.html),这里开始给反转加上了一些条件,当需要固定规律一段一段去处理字符串的时候,要想想在在for循环的表达式上做做文章。
|
||||
然后发现[541. 反转字符串II](https://programmercarl.com/0541.反转字符串II.html),这里开始给反转加上了一些条件,当需要固定规律一段一段去处理字符串的时候,要想想在for循环的表达式上做做文章。
|
||||
|
||||
后来在[151.翻转字符串里的单词](https://programmercarl.com/0151.翻转字符串里的单词.html)中,要对一句话里的单词顺序进行反转,发现先整体反转再局部反转 是一个很妙的思路。
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
||||
|
||||
什么是链表,链表是一种通过指针串联在一起的线性结构,每一个节点由两部分组成,一个是数据域一个是指针域(存放指向下一个节点的指针),最后一个节点的指针域指向null(空指针的意思)。
|
||||
|
||||
链接的入口节点称为链表的头结点也就是head。
|
||||
链表的入口节点称为链表的头结点也就是head。
|
||||
|
||||
如图所示:
|
||||

|
||||
|
@ -155,23 +155,28 @@ public class Solution {
|
||||
|
||||
class Solution:
|
||||
def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
|
||||
"""
|
||||
根据快慢法则,走的快的一定会追上走得慢的。
|
||||
在这道题里,有的链表短,他走完了就去走另一条链表,我们可以理解为走的快的指针。
|
||||
|
||||
那么,只要其中一个链表走完了,就去走另一条链表的路。如果有交点,他们最终一定会在同一个
|
||||
位置相遇
|
||||
"""
|
||||
if headA is None or headB is None:
|
||||
return None
|
||||
cur_a, cur_b = headA, headB # 用两个指针代替a和b
|
||||
|
||||
|
||||
while cur_a != cur_b:
|
||||
cur_a = cur_a.next if cur_a else headB # 如果a走完了,那么就切换到b走
|
||||
cur_b = cur_b.next if cur_b else headA # 同理,b走完了就切换到a
|
||||
|
||||
return cur_a
|
||||
lenA, lenB = 0, 0
|
||||
cur = headA
|
||||
while cur: # 求链表A的长度
|
||||
cur = cur.next
|
||||
lenA += 1
|
||||
cur = headB
|
||||
while cur: # 求链表B的长度
|
||||
cur = cur.next
|
||||
lenB += 1
|
||||
curA, curB = headA, headB
|
||||
if lenA > lenB: # 让curB为最长链表的头,lenB为其长度
|
||||
curA, curB = curB, curA
|
||||
lenA, lenB = lenB, lenA
|
||||
for _ in range(lenB - lenA): # 让curA和curB在同一起点上(末尾位置对齐)
|
||||
curB = curB.next
|
||||
while curA: # 遍历curA 和 curB,遇到相同则直接返回
|
||||
if curA == curB:
|
||||
return curA
|
||||
else:
|
||||
curA = curA.next
|
||||
curB = curB.next
|
||||
return None
|
||||
```
|
||||
|
||||
### Go
|
||||
@ -248,19 +253,21 @@ var getListLen = function(head) {
|
||||
}
|
||||
var getIntersectionNode = function(headA, headB) {
|
||||
let curA = headA,curB = headB,
|
||||
lenA = getListLen(headA),
|
||||
lenB = getListLen(headB);
|
||||
if(lenA < lenB) {
|
||||
// 下面交换变量注意加 “分号” ,两个数组交换变量在同一个作用域下时
|
||||
lenA = getListLen(headA), // 求链表A的长度
|
||||
lenB = getListLen(headB);
|
||||
if(lenA < lenB) { // 让curA为最长链表的头,lenA为其长度
|
||||
|
||||
// 交换变量注意加 “分号” ,两个数组交换变量在同一个作用域下时
|
||||
// 如果不加分号,下面两条代码等同于一条代码: [curA, curB] = [lenB, lenA]
|
||||
|
||||
[curA, curB] = [curB, curA];
|
||||
[lenA, lenB] = [lenB, lenA];
|
||||
}
|
||||
let i = lenA - lenB;
|
||||
while(i-- > 0) {
|
||||
let i = lenA - lenB; // 求长度差
|
||||
while(i-- > 0) { // 让curA和curB在同一起点上(末尾位置对齐)
|
||||
curA = curA.next;
|
||||
}
|
||||
while(curA && curA !== curB) {
|
||||
while(curA && curA !== curB) { // 遍历curA 和 curB,遇到相同则直接返回
|
||||
curA = curA.next;
|
||||
curB = curB.next;
|
||||
}
|
||||
|
Reference in New Issue
Block a user