Leetcode-review

索引

题单为leetcode经典150

数组 / 字符串

68. 文本左右对齐

68. 文本左右对齐 - 力扣(LeetCode)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
class Solution:
def fullJustify(self, words: List[str], maxWidth: int) -> List[str]:
ans=[]
word_list=[]
cur_len = 0
for word in words:
if cur_len + len(word) + len(word_list) > maxWidth:
spaces = maxWidth - cur_len
gaps = len(word_list) - 1
if gaps == 0:
line = word_list[0] + ' ' * spaces
else:
average,left = divmod(spaces,gaps)
line = ''
for i in range(gaps):
line += word_list[i]
line += average* ' '
if i<left:
line +=' '
line += word_list[-1]
ans.append(line)
#initialize
word_list = []
cur_len = 0
word_list.append(word)
cur_len += len(word)
#最后一行
line = ' '.join(word_list)
spaces = maxWidth - len(line)
line += ' ' * spaces
ans.append(line)

return ans

一开始先写了处理溢出的情况,不过中间还需要先存储那些可以的word再合成一个line

思路就是一行一行读一行一行造,里面有一个问题是在这里

1
2
3
4
5
for i in range(gaps):
line += word_list[i]
line += average* ' '
if i<left:
line +=' '

这个i<left我想了很久

left是余数,i是中间有的空格-1,这边要的效果是把余数在前面的空里面填满

那假设有3个要填的,有四个空格,要填的i是0,1,2,此时left=3

5个要填的,有七个空格,要填的i是0,1,2,3,4,此时left=5

那很明显可以用i<left来限制

然后就造吧

392. 判断子序列

1
2
3
4
class Solution:
def isSubsequence(self, s: str, t: str) -> bool:
it = iter(t)
return all(c in it for c in s)

迭代器神力,同时判断是不是在里面
同时使用all( )

1312. 让字符串成为回文串的最少插入次数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Solution:
def minInsertions(self, s: str) -> int:
re_str=s[::-1]
def longestCommonSubsequence(text1: str, text2: str) -> int:
m = len(text1)
n = len(text2)

dp = [[0] * (n + 1) for _ in range(m + 1)]
for i in range(1, m + 1):
for j in range(1, n + 1):
if text1[i - 1] == text2[j - 1]:
dp[i][j] = dp[i - 1][j - 1] + 1
else:
dp[i][j] = max(dp[i - 1][j], dp[i][j - 1])
return dp[m][n]

return len(s)-longestCommonSubsequence(s,re_str)

套用了另外一道简单题目lcs,第一次涉及dp

如何求lcs

1
2
3
4
5
6
7
8
9
10
11
12
def longestCommonSubsequence(text1: str, text2: str) -> int:
m = len(text1)
n = len(text2)

dp = [[0] * (n + 1) for _ in range(m + 1)]
for i in range(1, m + 1):
for j in range(1, n + 1):
if text1[i - 1] == text2[j - 1]:
dp[i][j] = dp[i - 1][j - 1] + 1
else:
dp[i][j] = max(dp[i - 1][j], dp[i][j - 1])
return dp[m][n]

m = "abccdca"
n = "adcaab" lcs = “aca”`

情况一:两个字符串的最后一个字符相等
如果 text1[i-1] == text2[j-1]

  • 这意味着我们找到了一个公共字符!这个字符必然可以作为它们公共子序列的一部分。
  • 那么,text1 的前 i 个字符和 text2 的前 j 个字符的LCS,就等于它们各自去掉最后一个字符后的LCS长度再加1
  • 用 dp 数组来表示就是:dp[i][j] = dp[i-1][j-1] + 1

举例: 求 “abc” 和 “adc” 的LCS。因为最后一个字符 ‘c’ 相等,问题就转化为求 “ab” 和 “ad” 的LCS长度,然后加1。

情况二:两个字符串的最后一个字符不相等
如果 text1[i-1] != text2[j-1]

  • 这意味着这两个不同的字符不可能同时出现在LCS的末尾。
  • 那么,我们就要在两种可能性中取一个较大值:
    1. text1 的前 i 个字符和 text2 的前 j-1 个字符的LCS长度(相当于把 text2 的最后一个字符扔掉,看看结果)。这个值就是 dp[i][j-1]
    2. text1 的前 i-1 个字符和 text2 的前 j 个字符的LCS长度(相当于把 text1 的最后一个字符扔掉,看看结果)。这个值就是 dp[i-1][j]
  • 我们取这两者中的最大值,因为它代表了更长的公共子序列。
  • 用 dp 数组来表示就是:dp[i][j] = max(dp[i-1][j], dp[i][j-1])

这题看题解去吧,俺也懵懵的

3354. 使数组元素等于零 - 力扣(LeetCode)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Solution:
def countValidSelections(self, nums: List[int]) -> int:
num_sum= sum(nums)
left_sum = 0
ans = 0
right_sum = num_sum
for num in nums:
if num == 0:
if left_sum == right_sum:
ans+=2
elif left_sum - right_sum == 1 or right_sum - left_sum == 1:
ans+=1
else:
left_sum+=num
right_sum=num_sum-left_sum
return ans


思路非常简单,发现题目根本没必要使用动态的想法

双指针

167. 两数之和 II - 输入有序数组 - 力扣(LeetCode)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Solution:
def twoSum(self, numbers: List[int], target: int) -> List[int]:
index1=0
index2=0
for index,num in enumerate(numbers):
requirement=target-num
if requirement in numbers:
index1=index+1
if num == requirement:
index2 = numbers.index(requirement, index1) + 1
return [index1, index2]
else:
index2 = numbers.index(requirement) +1
return [index1,index2]

这是第一次ac代码,执行用时分布 5813ms 击败5.20%
没错高贵的O(n^2),那可得好好优化一下了

在这应该使用双指针来快速查找,避免多次遍历

1
2
3
4
5
6
7
8
9
10
11
12
class Solution:
def twoSum(self, numbers: List[int], target: int) -> List[int]:
left=0
right=len(numbers)-1
while left < right:
cur_sum=numbers[left]+numbers[right]
if cur_sum==target:
return [left+1,right+1]
elif cur_sum < target:
left+=1
else:
right-=1

该方法时间复杂度为O(n) 执行用时分布 4ms 击败50.86%
奇怪,为什么一样的算法他们能跑到0ms的,是我没充钱吗?

11. 盛最多水的容器 - 力扣(LeetCode)

贪心双指针一遍过

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Solution:
def maxArea(self, height: List[int]) -> int:
max_volume=0
left=0
right=len(height)-1
while(left!=right):
x=right-left
y=min(height[left],height[right])
v=x*y
if v>max_volume:
max_volume=v
if height[left]>=height[right]:
right-=1
else:
left+=1
return max_volume

15. 三数之和 - 力扣(LeetCode)

这是第一版🔟山,最后tle了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
class Solution:
def threeSum(self, nums: List[int]) -> List[List[int]]:
if len(nums) < 3:
return []
sorted_nums = sorted(nums)
count = 0
for num in sorted_nums:
if num < 0:
count += 1
nums1 = sorted_nums[:count]
nums2 = sorted_nums[count:]
if not nums1 or not nums2:
if sorted_nums.count(0) >= 3:
return [[0, 0, 0]]
return []
ans = []
seen = []
for i in nums1:
for j in nums2:
k = -i - j
if k not in sorted_nums:
continue
if [i, j, k].count(i) > sorted_nums.count(i):
continue
if [i, j, k].count(j) > sorted_nums.count(j):
continue
if [i, j, k].count(k) > sorted_nums.count(k):
continue

triple = sorted([i, j, k])
if triple not in seen:
seen.append(triple)
ans.append(triple)

if sorted_nums.count(0) >= 3:
ans.append([0, 0, 0])
return ans

这是高贵的O(n^3)算法,暴力的后果还是被卡了啊,同时内存也多到爆炸,于是想到三指针

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class Solution:
def threeSum(self, nums: List[int]) -> List[List[int]]:
ans=[]
nums.sort()
n=len(nums)
for i in range(n-2):
if i > 0 and nums[i]==nums[i-1]:
continue
left=i+1
right=n-1
while left < right:
s = nums[i]+nums[left]+nums[right]
if s==0:
ans.append([nums[i],nums[left],nums[right]])
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
elif s<0:
left+=1
else:
right-=1
return ans

滑动窗口

209. 长度最小的子数组 - 力扣(LeetCode)

滑动窗口初尝试,好像不难,和双指针很像了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Solution:
def minSubArrayLen(self, target: int, nums: List[int]) -> int:
n=len(nums)
ans=n+1
s=0
left=0
for right,num in enumerate(nums):
s+=num
while s>=target:
ans=min(ans,right-left+1)
s-=nums[left]
left+=1
if ans==n+1:return 0
return ans

3. 无重复字符的最长子串 - 力扣(LeetCode)

滑动窗口+hashmap

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Solution:
def lengthOfLongestSubstring(self, s: str) -> int:
start = 0
seen = set()
maxlen = 0

for end in range(len(s)):
while s[end] in seen:
seen.remove(s[start])
start += 1
seen.add(s[end])
maxlen = max(maxlen, end - start + 1)

return maxlen

LCR 167. 招式拆解 I - 力扣(LeetCode)是一样的,因此一起过了

30. 串联所有单词的子串 - 力扣(LeetCode)

一开始思路不好,神秘的O(n!xn)算法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class Solution:
def generate_permutations(self,words:str) -> List[str]:
if len(words) == 1:
return words
res = []
for i in range(len(words)):
first = words[i]
rest = words[:i] + words[i+1:]
for sub in self.generate_permutations(rest):
res.append(first + sub)
return res

def findSubstring(self, s: str, words: List[str]) -> List[int]:
sub_words = set(self.generate_permutations(words))
l=len(s)
window = len(words[0]) * len(words)
if window > len(s): return []
ans=[]
for start in range(0, len(s) - window + 1):
if s[start : start + window] in sub_words:
ans.append(start)
return ans



124 / 182 个通过的测试用例
提交于 2025.10.30 21:35
s ="fffffffffffffffffffffffffffffffff"
words =["a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a","a"]
很明显会因为生成子串的过程太长导致tle
所以换一个思路,把words用键值对一一对应

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class Solution:
def findSubstring(self, s: str, words: List[str]) -> List[int]:
if not s or not words:
return []
word_len = len(words[0])
total_len = word_len * len(words)
word_map = {w: words.count(w) for w in words}
ans = []
n = len(s)
for i in range(0, n - total_len + 1):
seen = {}
j = 0
while j < len(words):
word_start = i + j * word_len
word_end = word_start + word_len
word = s[word_start:word_end]
if word not in word_map:
break
seen[word] = seen.get(word, 0) + 1
if seen[word] > word_map[word]:
break
j += 1
if j == len(words):
ans.append(i)
return ans

30. 串联所有单词的子串 - 力扣(LeetCode)
这测试点诗人啊
181 / 182 个通过的测试用例

ac代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
class Solution:
def findSubstring(self, s: str, words: List[str]) -> List[int]:
if not s or not words:
return []
word_len = len(words[0])
total_len = word_len * len(words)
word_map = {w: words.count(w) for w in words}
ans = []
n = len(s)
for offset in range(word_len):
left = offset
seen = {}
count = 0
for right in range(offset, n - word_len + 1, word_len):
word = s[right:right+word_len]
if word in word_map:
seen[word] = seen.get(word, 0) + 1
count += 1
while seen[word] > word_map[word]:
left_word = s[left:left+word_len]
seen[left_word] -= 1
left += word_len
count -= 1
if count == len(words):
ans.append(left)
else:
seen.clear()
count = 0
left = right + word_len
return ans

最快的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
class Solution:
def findSubstring(self, s: str, words: List[str]) -> List[int]:
n = len(s)
step = len(words[0])
total_len = step * len(words)
res = []
for i in range(step):
map_word_cnt = {}
for word in words:
if word not in map_word_cnt:
map_word_cnt[word] = 1
else:
map_word_cnt[word] += 1
match_cnt = len(words)
right = i
while right + step - 1 < n:
left = right + step - total_len
left_out = left - step
if left_out >= 0:
w_left_out = s[left_out:left_out+step]
if w_left_out in map_word_cnt:
map_word_cnt[w_left_out] += 1
if map_word_cnt[w_left_out] > 0:
match_cnt += 1
w_right = s[right:right+step]
if w_right in map_word_cnt:
map_word_cnt[w_right] -= 1
if map_word_cnt[w_right] >= 0:
match_cnt -= 1
if left >= 0 and match_cnt == 0:
res.append(left)
right += step
return res

76. 最小覆盖子串 - 力扣(LeetCode)

滑动窗口 哈希表

如果min_len=len(s)会导致维护出错

使用哈希表还是不熟练
.items()忘了

还有一个注意点是切片,切片左闭右开 [left , right + 1) 老记错
right-left+1 是长度

滑动窗口从窗口为零开始,向右扩张,同时维护window_counts ,一边向右添加一边保持左边没有额外的字符
就这样遍历,复杂度O(N) 600ms 击败44.06%

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
class Solution:
def count(self, t: str) -> dict:
t_count = {}
for char in t:
if char in t_count:
t_count[char] += 1
else:
t_count[char] = 1
return t_count

def check(self, current_dict: dict, t_count: dict) -> bool:
for char, required_count in t_count.items():
if current_dict.get(char, 0) < required_count:
return False
return True

def minWindow(self, s: str, t: str) -> str:
t_count = self.count(t)
window_counts = {}
left = 0
min_len = len(s) + 1
result = ""

for right in range(len(s)):
char_in = s[right]
window_counts[char_in] = window_counts.get(char_in, 0) + 1

while self.check(window_counts, t_count):
current_len = right - left + 1
if current_len < min_len:
min_len = current_len
result = s[left : right + 1]

char_out = s[left]
window_counts[char_out] -= 1

if window_counts[char_out] == 0:
del window_counts[char_out]

left += 1
return result

这次想法里面的问题所在是这块

1
2
3
4
5
def check(self, current_dict: dict, t_count: dict) -> bool:
for char, required_count in t_count.items():
if current_dict.get(char, 0) < required_count:
return False
return True

这个循环的次数取决于 t 中有多少个 不重复 的字符
但是如果字典有27个字符的时候就很明显不合理了
而且check了非常非常多次,也浪费了很多的时间
看看这个代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class Solution:
def minWindow(self, s: str, t: str) -> str:
need=defaultdict(int)
for c in t:
need[c]+=1
needCnt=len(t)
i=0
res=(0,float('inf'))
for j,c in enumerate(s):
if need[c]>0:
needCnt-=1
need[c]-=1
if needCnt==0:
while True:
c=s[i]
if need[c]==0:
break
need[c]+=1
i+=1
if j-i<res[1]-res[0]:
res=(i,j)
need[s[i]]+=1
needCnt+=1
i+=1
return ''if res[1]>len(s) else s[res[0]:res[1]+1]

在这边发现了defaultdict,这才知道leetcode已经import过了collections
那这块内容需要好好学一学,写到Python-algorithm去

矩阵

36. 有效的数独 - 力扣(LeetCode)

这题只要判断是否合理,不需要解出来数独其实还好
一次遍历就行了
用set来创建集合

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Solution:
def isValidSudoku(self, board: List[List[str]]) -> bool:
rows = [set() for _ in range(9)]
cols = [set() for _ in range(9)]
boxes = [set() for _ in range(9)]

for i in range(0,9):
for j in range(0,9):
num = board[i][j]
if num == '.':
continue
if num in rows[i]:
return False
rows[i].add(num)
if num in cols[j]:
return False
cols[j].add(num)

box_index = (i // 3) * 3 + (j // 3)
if num in boxes[box_index]:
return False
boxes[box_index].add(num)
return True

54. 螺旋矩阵 - 力扣(LeetCode)

我的思路是用上下左右限制,有点复杂,维护起来也好累。。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class Solution:
def spiralOrder(self, matrix: List[List[int]]) -> List[int]:
if not matrix or not matrix[0]:
return []
ans = []
num_rows = len(matrix)
num_cols = len(matrix[0])

left, right = 0, num_cols - 1
top, bottom = 0, num_rows - 1

while left <= right and top <= bottom:
for col in range(left, right + 1):
ans.append(matrix[top][col])
top += 1
for row in range(top, bottom + 1):
ans.append(matrix[row][right])
right -= 1
if not (left <= right and top <= bottom):
break
for col in range(right, left - 1, -1):
ans.append(matrix[bottom][col])
bottom -= 1
for row in range(bottom, top - 1, -1):
ans.append(matrix[row][left])
left += 1
return ans

但看官方第二种解法是这样的
对于每层,从左上方开始以顺时针的顺序遍历所有元素。假设当前层的左上角位于 (top,left),右下角位于 (bottom,right),按照如下顺序遍历当前层的元素。

从左到右遍历上侧元素,依次为 (top,left) 到 (top,right)。

从上到下遍历右侧元素,依次为 (top+1,right) 到 (bottom,right)。

如果 left<right 且 top<bottom,则从右到左遍历下侧元素,依次为 (bottom,right−1) 到 (bottom,left+1),以及从下到上遍历左侧元素,依次为 (bottom,left) 到 (top+1,left)。

遍历完当前层的元素之后,将 left 和 top 分别增加 1,将 right 和 bottom 分别减少 1,进入下一层继续遍历,直到遍历完所有元素为止。

48. 旋转图像 - 力扣(LeetCode)

想法很多都不好实现。
没写,但是看到了一个逆天答案

1
2
3
4
class Solution:
def rotate(self, matrix: List[List[int]]) -> None:
matrix[:] = list(map(list, zip(*matrix)))
for row in matrix: row.reverse()

73. 矩阵置零 - 力扣(LeetCode)

思路非常简单,找到0的位置,然后直接改,这题目凭什么是中档题?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Solution:
def setZeroes(self, matrix: List[List[int]]) -> None:
"""
Do not return anything, modify matrix in-place instead.
"""
rows = len(matrix)
cols = len(matrix[0])
temp = []
for i in range(rows):
for j in range(cols):
if matrix[i][j] == 0:
temp.append([i, j])

for r, c in temp:
for j in range(cols):
matrix[r][j] = 0
for i in range(rows):
matrix[i][c] = 0

但由于使用了temp存储,导致空间复杂度为O(M+N)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Solution:
def setZeroes(self, matrix: List[List[int]]) -> None:
m, n = len(matrix), len(matrix[0])
flag_col0 = False

for i in range(m):
if matrix[i][0] == 0:
flag_col0 = True
for j in range(1, n):
if matrix[i][j] == 0:
matrix[i][0] = matrix[0][j] = 0

for i in range(m - 1, -1, -1):
for j in range(1, n):
if matrix[i][0] == 0 or matrix[0][j] == 0:
matrix[i][j] = 0
if flag_col0:
matrix[i][0] = 0

这个是leetcode官方给出的空间复杂度为O(1)的算法
如果 matrix[i][j]是 0,它就把这个信息记录在 matrix[i][0]和 matrix[0][j] 上,将它们也设置为 0。
这样一来,matrix[i][0]就成了第 i 行是否需要置零的标记位。
同理,matrix[0][j]就成了第 j 列是否需要置零的标记位。
很巧妙的直接使用原矩阵在不破坏的情况下标记并且置零,不额外开空间

289. 生命游戏 - 力扣(LeetCode)

充满小巧思了
第一个小巧思是使用元组来传neighbor,然后python会自动解包,写起来好看
第二个小巧思是要判断当前状态:状态 1 和 2 都代表“原来是活的”,状态 0 和 3 都代表“原来是死的”
这样区分避免出现在修改过程中误判的情况,最后第二次遍历把状态再修正
和官方第二个题解差不多,但是官方只用到2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class Solution:
def gameOfLife(self, board: List[List[int]]) -> None:
"""
Do not return anything, modify board in-place instead.
"""
m, n = len(board), len(board[0])
neighbors = [(1, 0), (-1, 0), (0, 1), (0, -1), (1, 1), (1, -1), (-1, 1), (-1, -1)]
for i in range(m):
for j in range(n):
alive = 0
for dx, dy in neighbors:
r, c = i + dx, j + dy
if 0 <= r < m and 0 <= c < n:
if board[r][c] == 1 or board[r][c] == 2:
alive += 1
if board[i][j] == 1 and (alive < 2 or alive > 3):
board[i][j] = 2
elif board[i][j] == 0 and alive == 3:
board[i][j] = 3

for i in range(m):
for j in range(n):
if board[i][j] == 2:
board[i][j] = 0
elif board[i][j] == 3:
board[i][j] = 1

哈希表

383. 赎金信 - 力扣(LeetCode)

用Counter自动计数
然后直接在本体上操作就行

1
2
3
4
5
6
7
8
9
10
11
12
13
class Solution:
def canConstruct(self, ransomNote: str, magazine: str) -> bool:
if len(ransomNote) > len(magazine):
return False
magazine_counts = Counter(magazine)

for char in ransomNote:
if magazine_counts[char] > 0:
magazine_counts[char] -= 1
else:
return False

return True

这样写也可以

1
2
3
4
5
6
7
8
9
10
11
12
class Solution:
def canConstruct(self, ransomNote: str, magazine: str) -> bool:
if len(ransomNote)>len(magazine) or len(set(magazine)) < len(set(ransomNote)):
return False
count = {}
for i in magazine:
count[i] = count.get(i,0)+1
for i in ransomNote:
if count.get(i, 0) == 0:
return False
count[i] -= 1
return True

205. 同构字符串 - 力扣(LeetCode)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Solution:
def isIsomorphic(self, s: str, t: str) -> bool:
if len(s)!=len(t):
return False
s2tdict={}
t2sdict={}
for sstr,tstr in zip(s,t):
if sstr in s2tdict and s2tdict[sstr]!=tstr:
return False
if tstr in t2sdict and t2sdict[tstr]!=sstr:
return False
s2tdict[sstr]=tstr
t2sdict[tstr]=sstr
return True

但是zip()用法太别致了吧

1
2
3
class Solution:
def isIsomorphic(self, s: str, t: str) -> bool:
return len(set(s)) == len(set(t)) == len(set(zip(s, t)))

被吓哭了
也许应该复习一下set()和zip()
set(t)创建的是t中所有不重复字符的集合
zip(s, t) 会生成一系列的配对元组(tuple):
(‘p’, ‘t’), (‘a’, ‘i’), (‘p’, ‘t’), (‘e’, ‘l’), (‘r’, ‘e’)
这些配对就代表了 s 到 t 的映射关系。例如,第一个 ‘p’ 映射到 ‘t’,‘a’ 映射到 ‘i’,第二个 ‘p’ 也映射到 ‘t’。
因此映射和set()长度相同的情况下就可以得出结论

290. 单词规律 - 力扣(LeetCode)

和上一题同一个道理

1
2
3
4
5
class Solution:
def wordPattern(self, pattern: str, s: str) -> bool:
s2list=s.split(" ")
p2list=list(pattern)
return len(s2list)==len(p2list) and len(set(zip(s2list,p2list)))==len(set(s2list))==len(set(p2list))

思路:s2listp2list
首先两个长度要相等
然后要保证set出来的长度也相同
eg:
“abba”“wow mom mom wow”
set(list(“abba”))={“a”,“b”}
set(list(“wow mom mom wow”.split(" ")))={“wow”,“mom”}
set(zip(s2list,p2list))={(“a”,“wow”),(“b”,“mom”)}

242. 有效的字母异位词 - 力扣(LeetCode)

1
2
3
4
5
6
7
8
9
class Solution:
def isAnagram(self, s: str, t: str) -> bool:
s2list=list(s)
t2list=list(t)
scounter=Counter(s2list)
tcounter=Counter(t2list)
if scounter==tcounter:
return True
return False

其实"str"可以直接到Counter里面去使用
直接return Counter(t)==Counter(s)就结束了
或者也可以使用sorted(),return sorted(t)==sorted(s)

49. 字母异位词分组 - 力扣(LeetCode)

1
2
3
4
5
6
7
8
class Solution:
def groupAnagrams(self, strs: List[str]) -> List[List[str]]:
anagram_map = defaultdict(list)
for s in strs:
sorted_s=str(sorted(s))
anagram_map[sorted_s].append(s)

return list(anagram_map.values())

复杂度是O(Nklogk),有点高了

1
2
3
4
5
6
7
8
9
10
11
12
13
class Solution:
def groupAnagrams(self, strs: List[str]) -> List[List[str]]:
if len(strs) == 1:
return [strs]
ans= {}
for ss in strs:
s = str(sorted(ss))
if s not in ans :
ans[s] = [ss]
else :
ans[s].append(ss)

return list(ans.values())

这样一个道理

1
2
3
4
5
6
7
8
9
class Solution:
def groupAnagrams(self, strs: List[str]) -> List[List[str]]:
mp = collections.defaultdict(list)

for str in strs:
key=''.join(sorted(str))
mp[key].append(str)

return list(mp.values())

1. 两数之和 - 力扣(LeetCode)

哈希

1
2
3
4
5
6
7
8
9
class Solution:
def twoSum(self, nums: List[int], target: int) -> List[int]:
num_map = {}
for i, num in enumerate(nums):
complement = target - num
if complement in num_map:
return [num_map[complement], i]
num_map[num] = i
return []Q

202. 快乐数 - 力扣(LeetCode)

第一版
371 / 420 个通过的测试用例

1
2
3
4
5
6
7
8
9
10
11
12
13
class Solution:
def isHappy(self, n: int) -> bool:
while n/10>1:
if n==1:
return True
sum=0
n2str=str(n)
for num in n2str:
sum+=(int(num))**2
n=sum
if n==1:
return True
return False

while那边的判断条件写错了,看到测试用例7,在一开始就返回false了,但是迭代到最后是可以到1的

第二版

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Solution:
def isHappy(self, n: int) -> bool:
seen = set()
while n != 1 and n not in seen:
seen.add(n)

total_sum = 0
n2str = str(n)
for digit in n2str:
total_sum += int(digit) ** 2

n = total_sum

return n==1

时间复杂度O(Log(N)),7ms在这个题目里算最慢的一档了

1
2
3
4
5
6
7
8
9
10
11
12
class Solution:
def isHappy(self, n: int) -> bool:
result = []
while n not in result:
result.append(n)
s = 0
for i in str(n):
s+=int(i)**2
if s == 1:
return True
n = s
return False

4ms
稍微快了一些

219. 存在重复元素 II - 力扣(LeetCode)

思路:用map存,时间复杂度O(N),

1
2
3
4
5
6
7
8
class Solution:
def containsNearbyDuplicate(self, nums: List[int], k: int) -> bool:
num_map={}
for i, num in enumerate(nums):
if num in num_map and i - num_map[num] <= k:
return True
num_map[num] = i
return False

官方第二个滑动窗口
思路是维护k+1大小的set

1
2
3
4
5
6
7
8
9
10
11
class Solution:
def containsNearbyDuplicate(self, nums: List[int], k: int) -> bool:
s = set()
for i, num in enumerate(nums):
if i > k:
s.remove(nums[i - k - 1])
if num in s:
return True
s.add(num)
return False

128. 最长连续序列 - 力扣(LeetCode)

思路:去重,然后迭代,哈希表

1
2
3
4
5
6
7
8
9
10
11
12
13
class Solution:
def longestConsecutive(self, nums: List[int]) -> int:
num_set = set(nums)
longest_streak = 0
for num in num_set:
if num - 1 not in num_set:
current_num = num
current_streak = 1
while current_num + 1 in num_set:
current_num += 1
current_streak += 1
longest_streak = max(longest_streak, current_streak)
return longest_streak

数学

9. 回文数 - 力扣(LeetCode)

1
2
3
4
5
6
7
8
9
10
11
12
func isPalindrome(x int) bool {
if x < 0 || (x % 10 == 0 && x != 0){
return false
}
revertedNum := 0
for x > revertedNum {
revertedNum = revertedNum * 10 + x % 10
x /= 10
}

return x == revertedNum || x == revertedNum / 10
}

66. 加一 - 力扣(LeetCode)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
func plusOne(digits []int) []int {
n := len(digits)
for i := n - 1; i >= 0; i--{
if digits[i] != 9{
digits[i]++
for j:= i+1; j <= n - 1;j++{
digits[j] = 0
}
return digits
}
}

digits = make([]int,n+1)
digits[0] = 1
return digits
}

172. 阶乘后的零 - 力扣(LeetCode)

1
2
3
4
5
6
7
8
9
func trailingZeroes(n int) int {
ans := 0
for i := 5; i <= n; i += 5 {
for x := i; x % 5 == 0; x /= 5 {
ans++
}
}
return ans
}

69. x 的平方根 - 力扣(LeetCode)

二分查找

1
2
3
4
5
6
7
8
9
10
11
12
13
14
func mySqrt(x int) int {
l, r := 0, x
ans := -1
for l <= r {
mid := l + (r - l) / 2
if mid * mid <= x {
ans = mid
l = mid + 1
} else {
r = mid -1
}
}
return ans
}

50. Pow(x, n) - 力扣(LeetCode)

初版 TLE 代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
func myPow(x float64, n int) float64 {
var ans float64 = x
if n > 0 {
for i := n - 1; i > 0; i-- {
ans *= x
}
} else if n < 0 {
for i := n; i <= 0; i++ {
ans /= x
}
} else {
ans = 1.0
}
return ans
}

AC

快速幂+递归

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
func myPow(x float64, n int) float64 {
if n >= 0 {
return quickMul(x,n)
}
return 1.0 / quickMul(x, -n)
}

func quickMul(x float64, n int) float64 {
if n == 0 {
return 1
}
y := quickMul(x, n /2)
if n % 2 == 0 {
return y * y
}
return y * y * x
}

149. 直线上最多的点数 - 力扣(LeetCode)

真恶心,谁面试出这题目我就敢光速跑路

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
func maxPoints(points [][]int) (ans int) {
for i, p := range points {
x, y := p[0], p[1]
cnt := map[float64]int{}
for _, q := range points[i+1:] {
dx, dy := q[0]-x, q[1]-y
k := math.MaxFloat64
if dx != 0 {
k = float64(dy) / float64(dx)
}
cnt[k]++
ans = max(ans, cnt[k])
}
}
return ans + 1
}

区间

56. 合并区间 - 力扣(LeetCode)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
func merge(intervals [][]int) [][]int {
if (len(intervals) == 1) {
return intervals
}
sort.Slice(intervals, func(i, j int) bool {
return intervals[i][0] < intervals[j][0]
})
res := make([][]int, 0)
res = append(res, intervals[0])
for i := 1; i < len(intervals); i++ {
if (res[len(res)-1][1] >= intervals[i][0]) {
res[len(res)-1][1] = max(res[len(res)-1][1], intervals[i][1])
} else {
res = append(res, intervals[i])
}
}
return res
}

57. 插入区间 - 力扣(LeetCode)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
func insert(intervals [][]int, newInterval []int) [][]int {
res := make([][]int, 0)
i := 0
n := len(intervals)

for i < n && newInterval[0] > intervals[i][1] {
res = append(res, intervals[i])
i++
}

for i < n && intervals[i][0] <= newInterval[1] {
newInterval[0] = min(newInterval[0], intervals[i][0])
newInterval[1] = max(newInterval[1], intervals[i][1])
i++
}
res = append(res, newInterval)
for i < n {
res = append(res, intervals[i])
i++
}
return res
}

452. 用最少数量的箭引爆气球 - 力扣(LeetCode)

贪心

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
func findMinArrowShots(points [][]int) int {
res := 1
sort.Slice(points, func(i, j int) bool{
return points[i][1] < points[j][1]
})
arr := points[0][1]
for i := 1; i < len(points); i++ {
if points[i][0] > arr {
res += 1
arr = points[i][1]
}
}

return res
}

20. 有效的括号 - 力扣(LeetCode)

栈入门

golang里面没用自带的栈

因此使用切片来模拟栈

就是当动态数组用了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
func isValid(s string) bool {
n := len(s)
if n % 2 == 1 {
return false
}

pairs := map[byte] byte {
')': '(',
']': '[',
'}': '{',
}
stack := []byte{}
for i := 0; i < n; i++ {
if pairs[s[i]] > 0 {
if len(stack) == 0 || stack[len(stack)-1] != pairs[s[i]] {
return false
}
stack = stack[:len(stack)-1]
} else {
stack = append(stack, s[i])
}
}
return len(stack) == 0
}

71. 简化路径 - 力扣(LeetCode)

栈继续尝试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
func simplifyPath(path string) string {
parts := strings.Split(path, "/")

stack := []string{}

for _ , part := range parts {
if part == "" || part == "." {
continue
}
if part == ".." {
if len(stack) > 0 {
stack = stack[:len(stack)-1]
}
} else {
stack = append(stack, part)
}
}
return "/" + strings.Join(stack, "/")
}

155. 最小栈 - 力扣(LeetCode)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
type MinStack struct {
stack []int
minStack []int
}


func Constructor() MinStack {
return MinStack {
stack: []int{},
minStack: []int{},
}
}


func (this *MinStack) Push(val int) {
this.stack = append(this.stack, val)
if len(this.minStack) == 0 {
this.minStack = append(this.minStack, val)
} else {
curMin := this.minStack[len(this.minStack)-1]
if val < curMin {
this.minStack = append(this.minStack, val)
} else {
this.minStack = append(this.minStack, curMin)
}
}
}


func (this *MinStack) Pop() {
this.stack = this.stack[:len(this.stack)-1]
this.minStack = this.minStack[:len(this.minStack)-1]
}


func (this *MinStack) Top() int {
return this.stack[len(this.stack)-1]
}


func (this *MinStack) GetMin() int {
return this.minStack[len(this.stack)-1]
}


/**
* Your MinStack object will be instantiated and called as such:
* obj := Constructor();
* obj.Push(val);
* obj.Pop();
* param_3 := obj.Top();
* param_4 := obj.GetMin();
*/

150. 逆波兰表达式求值 - 力扣(LeetCode)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
func evalRPN(tokens []string) int {
stack := []int{}

for _ , token := range tokens {
if token == "+" {
b := stack[len(stack)-1]
a := stack[len(stack)-2]
stack = stack[:len(stack)-2]
stack = append(stack, a + b)
} else if token == "-" {
b := stack[len(stack)-1]
a := stack[len(stack)-2]
stack = stack[:len(stack)-2]
stack = append(stack, a - b)
} else if token == "*" {
b := stack[len(stack)-1]
a := stack[len(stack)-2]
stack = stack[:len(stack)-2]
stack = append(stack, a * b)
} else if token == "/" {
b := stack[len(stack)-1]
a := stack[len(stack)-2]
stack = stack[:len(stack)-2]
stack = append(stack, a / b)
} else {
num , _ := strconv.Atoi(token)
stack = append(stack, num)
}
}
return stack[0]
}

看了一下官方解法确实好很多,不看我都忘记switch了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
func evalRPN(tokens []string) int {
stack := []int{}
for _, token := range tokens {
val, err := strconv.Atoi(token)
if err == nil {
stack = append(stack, val)
} else {
num1, num2 := stack[len(stack)-2], stack[len(stack)-1]
stack = stack[:len(stack)-2]
switch token {
case "+":
stack = append(stack, num1+num2)
case "-":
stack = append(stack, num1-num2)
case "*":
stack = append(stack, num1*num2)
default:
stack = append(stack, num1/num2)
}
}
}
return stack[0]
}

224. 基本计算器 - 力扣(LeetCode)

不想写栈了,好烦

这题没想出来,hard 还是你 hard

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
func calculate(s string) int {
stack := []int{}
var ans int = 0
var num int = 0
var op int = 1

stack = append(stack, op)

for _, st := range s {
if st == ' ' {
continue
}
// 判断数字字符
if st >= '0' && st <= '9' {
// 类型转换:rune -> int
num = num*10 + int(st-'0')
} else {
// 遇到运算符或括号,先把之前的数字结算到 ans
ans += op * num
num = 0
if st == '+' {
op = stack[len(stack)-1]
} else if st == '-' {
op = -stack[len(stack)-1]
} else if st == '(' {
// ( 号:将当前的 op 压入栈,作为括号内新的环境符号
stack = append(stack, op)
} else if st == ')' {
// ) 号:出栈,回到上一层环境
stack = stack[:len(stack)-1]
}
}
}
return ans + op*num
}

链表

141. 环形链表 - 力扣(LeetCode)

第一种,哈希表去存储路过的所有结点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/**
* Definition for singly-linked list.
* type ListNode struct {
* Val int
* Next *ListNode
* }
*/
func hasCycle(head *ListNode) bool {
seen := map[*ListNode]struct{}{}
for head != nil {
if _, ok := seen[head]; ok {
return true
}
seen[head] = struct{}{}
head = head.Next
}
return false
}

但是这边用法好多,需要慢慢理解

  • head *ListNode 很明显就是指针

  • map[*ListNode]struct{}{}:

  • Go内部没有Set()集合,要用Map映射来模拟集合

  • map[keyType]valueType 所以这边key*ListNode,valuestruct{}这样一个空结构体,0字节

  • 弄好这样一个map之后要初始化

  • nil == None

  • map查找 (comma-ok idiom)

  • if _ , ok := map[fuck]; ok { }

  • seen[head] = struct{}{}

  • 这边还是用.来选结构体内部内容

题目问有没有空间为O(1)的算法,这也就说明不能去用哈希表存了,理论上也在只能用指针那种,那当然就是了

快慢指针
「Floyd 判圈算法」

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
func hasCycle(head *ListNode) bool {
if head == nil || head.Next == nil {
return false
}
slow := head
fast := head

for fast != nil && fast.Next != nil {
slow = slow.Next
fast = fast.Next.Next

if slow == fast {
return true
}
}
return false
}

好吧官方题解给的更精简一点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
func hasCycle(head *ListNode) bool {
if head == nil || head.Next == nil {
return false
}
slow, fast := head, head.Next
for fast != slow {
if fast == nil || fast.Next == nil {
return false
}
slow = slow.Next
fast = fast.Next.Next
}
return true
}

然后起点有那么点不一样罢了,反正最后套圈就能套回来

2. 两数相加 - 力扣(LeetCode)

梦开始的地方到梦结束的地方一站式服务喵

这是我们leetcode第二题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
func addTwoNumbers(l1 *ListNode, l2 *ListNode) *ListNode {
var tail *ListNode
head := tail
carry := 0
for l1 != nil || l2 != nil {
n1, n2 := 0, 0
if l1 != nil {
n1 = l1.Val
l1 = l1.Next
}
if l2 != nil {
n2 = l2.Val
l2 = l2.Next
}
sum := n1 + n2 + carry
sum, carry = sum % 10, sum / 10
if head == nil {
head = &ListNode{Val: sum}
tail = head
} else {
tail.Next = &ListNode{Val: sum}
tail = tail.Next
}
}
if carry > 0 {
tail.Next = &ListNode{Val: carry}
}
return head
}

先来理思路吧,创建了一个新的链表tail,head是它的头结点

加法变成carry*10+sum,然后其实就结束了,不过我没用过这里的链表,这边这个链表的创建确实把我难住了

先创建头结点,头节点是一个地址+Val所以直接对ListNode{Val: sum}取地址存起来就行了

tail.Next = &ListNode{Val: sum}

三件事,创建ListNode,ListNode的Val设成sum,tail.Next指向该地址

Q:我有一个问题,如果ListNode{Val: sum}里面东西一样的时候,他们地址还一样吗?

A:不一样,它会在堆(heap)上再开一个空间

当然啦,还可以有更好的写法

虚拟头节点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
func addTwoNumbers(l1 *ListNode, l2 *ListNode) *ListNode {
dummy := &ListNode{Val: 0}
tail := dummy
carry := 0

for l1 != nil || l2 != nil || carry > 0 {
n1, n2 := 0, 0

if l1 != nil {
n1 = l1.Val
l1 = l1.Next
}
if l2 != nil {
n2 = l2.Val
l2 = l2.Next
}
sum := n1 + n2 + carry
sum, carry = sum % 10, sum / 10

newNode := &ListNode{Val: sum}
tail.Next = newNode
tail = tail.Next
}
return dummy.Next
}

可以看到我们把很多个判断条件省略了,不需要考虑太多可读性也很好zwz

但是还是想吐槽,链表写起来没用理解起来方便,太需要大脑和操作了

21. 合并两个有序链表 - 力扣(LeetCode)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
/**
* Definition for singly-linked list.
* type ListNode struct {
* Val int
* Next *ListNode
* }
*/
func mergeTwoLists(list1 *ListNode, list2 *ListNode) *ListNode {
dummy := &ListNode{Val: 0}
tail := dummy

for list1 != nil || list2 != nil {
n1, n2 := 101, 101
if list1 == nil {
n1 = 101
n2 = list2.Val
} else if list2 == nil {
n1 = list1.Val
n2 = 101
} else if list1 != nil && list2 != nil {
n1 = list1.Val
n2 = list2.Val
}
if n1 <= n2 {
tail.Next = list1
tail = tail.Next
list1 = list1.Next
} else {
tail.Next = list2
tail = tail.Next
list2 = list2.Next
}
}
return dummy.Next
}

过了,但是可以做得更好,里面的101很明显是看数据给到100就这样用的,顺便优化一下写法和算法

不能忘记了链表的特色,一串直接用了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
func mergeTwoLists(list1 *ListNode, list2 *ListNode) *ListNode {
dummy := &ListNode{Val: 0}
tail := dummy

for list1 != nil && list2 != nil {
if list1.Val <= list2.Val {
tail.Next = list1
list1 = list1.Next
} else {
tail.Next = list2
list2 = list2.Next
}
tail = tail.Next
}

if list1 != nil {
tail.Next = list1
} else {
tail.Next = list2
}
return dummy.Next
}

138. 随机链表的复制 - 力扣(LeetCode)

看哭了,但是其实意思就是深拷贝

那要怎么办呢,有random甚至会导致遍历的时候出现环的情况,所以完全不能这样

那怎么办呢,我抄你的码

抄都抄不明白

那就只能好好看看了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
/**
* Definition for a Node.
* type Node struct {
* Val int
* Next *Node
* Random *Node
* }
*/
var cachedNode map[*Node]*Node

func deepCopy(node *Node) *Node {
if node == nil {
return nil
}
if n, ok := cachedNode[node]; ok {
return n
}
newNode := &Node{Val: node.Val}
cachedNode[node] = newNode
newNode.Next = deepCopy(node.Next)
newNode.Random = deepCopy(node.Random)
return newNode
}

func copyRandomList(head *Node) *Node {
cachedNode = map[*Node]*Node{}
return deepCopy(head)
}

这是官方的第一种解法,官方说是回溯 + 哈希表

但不如说是DFS 深度优先搜索+ 哈希表

var cachedNode map[*Node]*Node全局变量

其实就是map[原链表地址]新创建的对应链表的地址

1
2
3
4
func copyRandomList(head *Node) *Node {
cachedNode = map[*Node]*Node{}
return deepCopy(head)
}

初始化cachedNode,递归

1
2
3
if node == nil {
return nil
}

空就别复制了

1
2
3
if n, ok := cachedNode[node]; ok {
return n
}

创建过对应关系的两个节点就直接用,不能再创

1
2
newNode := &Node{Val: node.Val}
cachedNode[node] = newNode

创建对应关系

当然还有别的方法

// ToDo

206. 反转链表 - 力扣(LeetCode)

你好

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/**
* Definition for singly-linked list.
* type ListNode struct {
* Val int
* Next *ListNode
* }
*/
func reverseList(head *ListNode) *ListNode {
if head == nil {
return nil
}
if head.Next == nil {
return head
}
next := head.Next
var prev *ListNode = nil
for next != nil {
next = head.Next
head.Next = prev
prev = head
head = next
}
return prev
}

写的有点好笑,return head return半天大脑没褶皱了,不过进步的地方是至少能写出来了😢

可以稍微优化一下,前面判断条件实际上可以在下面优化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/**
* Definition for singly-linked list.
* type ListNode struct {
* Val int
* Next *ListNode
* }
*/
func reverseList(head *ListNode) *ListNode {
var prev *ListNode = nil
curr := head // 去用curr来存当前的地方就不会因为head而乱七八糟的了

for curr != nil { // curr没遍历完的时候
next := curr.Next // 下一个目的地 ,如果curr.Next == nil的时候也考虑好了
curr.Next = prev // 反向
prev = curr // 准备移动,所以同步往前一步prev和curr
curr = next
}
return prev
}

92. 反转链表 II - 力扣(LeetCode)

哈哈我不适合做链表,做玉玉了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
/**
* Definition for singly-linked list.
* type ListNode struct {
* Val int
* Next *ListNode
* }
*/
func reverseBetween(head *ListNode, left int, right int) *ListNode {
dummy := &ListNode{Val: 0, Next: head}
preLeft := dummy

for i := 0; i < left - 1; i++ {
preLeft = preLeft.Next
}
curr := preLeft.Next
leftPtr := curr

var prev *ListNode = nil
for i := 0; i < right - left + 1; i++ {
next := curr.Next
curr.Next = prev
prev = curr
curr = next
}

preLeft.Next = prev
leftPtr.Next = curr
return dummy.Next
}

25. K 个一组翻转链表 - 力扣(LeetCode)

第一次ac代码

执行用时分布 3ms 击败1.36%

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
/**
* Definition for singly-linked list.
* type ListNode struct {
* Val int
* Next *ListNode
* }
*/

func reverseKGroup(head *ListNode, k int) *ListNode {
dummy := &ListNode{Val: 0, Next: head}
curr := head
n := 0
for curr != nil {
n++
curr = curr.Next
}
count := n / k

pre := dummy
curr = head
for i := 0; i < count; i++ {
groupTail := curr

var prev *ListNode = nil
for j := 0; j < k ; j++ {
next := curr.Next
curr.Next = prev
prev = curr
curr = next
}
pre.Next = prev
groupTail.Next = curr

pre = groupTail
}
return dummy.Next
}