classSolution:deftwoSum(self,A,t):""" :type A: List[int] :type t: int :rtype: List[int] """ n =len(A) lo, hi =0, n -1 ret = []while lo < hi: s = A[lo]+ A[hi]if s > t: hi -=1elif s < t: lo +=1else: ret.append(lo +1) ret.append(hi +1)breakreturn ret
给定一个包含 n 个整数的数组 nums,
判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?
找出所有满足条件且不重复的三元组。
注意:答案中不可以包含重复的三元组。
例如, 给定数组 nums = [-1, 0, 1, 2, -1, -4],
满足要求的三元组集合为:
[
[-1, 0, 1],
[-1, -1, 2]
]
思路
排序 + 首尾双指针
将第三个数当作前两个数的目标和,在两数之和的基础上套一层循环
难点在于如何去重(不借用 set)
python
classSolution:defthreeSum(self,A):""" :type A: List[int] :rtype: List[List[int]] """ A.sort() n =len(A) ret = []for i inrange(n -2):# 去重时注意判断条件if i >0and A[i]== A[i -1]:# 对第一个数去重continue t =-A[i] lo, hi = i +1, n -1while lo < hi: s = A[lo]+ A[hi]if s < t: lo +=1elif s > t: hi -=1else: ret.append([A[i], A[lo], A[hi]])# 先移动指针再去重 lo +=1# hi -= 1 # 不必要# 去重时注意判断条件while lo < hi and A[lo]== A[lo -1]:# 对第二个数去重 lo +=1# while lo < hi and A[hi] == A[hi + 1]: # 对第三个数去重(不必要)# hi -= 1return ret
给定一个包含 n 个整数的数组 nums 和一个目标值 target,
判断 nums 中是否存在四个元素 a,b,c 和 d ,使得 a + b + c + d 的值与 target 相等?
找出所有满足条件且不重复的四元组。
注意:
答案中不可以包含重复的四元组。
示例:
给定数组 nums = [1, 0, -1, 0, -2, 2],和 target = 0。
满足要求的四元组集合为:
[
[-1, 0, 0, 1],
[-2, -1, 1, 2],
[-2, 0, 0, 2]
]
Python(N 数之和)
defnSum(A,N,t,tmp,ret):iflen(A)< N or N <2or t < A[0]* N or t > A[-1]* N:# 结束条件returnif N ==2: lo, hi =0,len(A)-1while lo < hi: s = A[lo]+ A[hi]if s < t: lo +=1elif s > t: hi -=1else: ret.append(tmp + [A[lo], A[hi]]) lo +=1while lo < hi and A[lo]== A[lo -1]:# 去重 lo +=1else:for i inrange(len(A) - N +1):if i >0and A[i]== A[i -1]:# 去重continuenSum(A[i+1:], N-1, t-A[i], tmp + [A[i]], ret)classSolution:deffourSum(self,A,t):""" :type A: List[int] :type t: int :rtype: List[List[int]] """ A.sort() ret = []nSum(A, 4, t, [], ret)return ret
classSolution:defthreeSumClosest(self,A,t):""" :type A: List[int] :type t: int :rtype: int """ A.sort()# 先排序 n =len(A) ans = A[0]+ A[1]+ A[2]# 用一个特殊的值初始化for i inrange(n-2): lo, hi = i +1, n -1# 首尾指针while lo < hi: s = A[i]+ A[lo]+ A[hi]ifabs(s - t)<abs(ans - t): ans = sif ans == t:return ansif s < t: lo +=1else: hi -=1return ans
classSolution:deftwoSum5(self,A,t):""" :type A: List[int] :type t: int :rtype: List[int] """ n =len(A) lo, hi =0, n -1 A.sort()# 如果是首尾双指针,一般要求有序 cnt =0while lo < hi: s = A[lo]+ A[hi]if s <= t: cnt += hi-lo lo +=1else: hi -=1return cnt
代码说明
以 [2,7,11,15] 为例
第一轮:lo = 0, hi = 3
s = A[lo] + A[hi] = 17 <= 24
因此 [2, 15], [2, 11], [2, 7] 均满足,hi - lo = 3
lo += 1
第二轮:lo = 1, hi = 3
s = A[lo] + A[hi] = 22 <= 24
因此 [7, 15], [7, 11] 均满足,hi - lo = 2
lo += 1
第三轮:lo = 2, hi = 3
s = A[lo] + A[hi] = 26 > 24
hi -= 1
不满足 lo < hi,退出,因此总数量为 3 + 2 = 5
classSolution:defthreeSumSmaller(self,A,t):""" :type A: List[int] :type t: int :rtype: List[int] """ A.sort() n =len(A) cnt =0for i inrange(n -2): lo, hi = i +1, n -1while lo < hi: s = A[i]+ A[lo]+ A[hi]if s < t: cnt += hi - lo lo +=1else: hi -=1return cnt
classSolution:deftriangleNumber(self,A):""" :type A: List[int] :rtype: int """ A.sort() n =len(A) cnt =0for i inrange(2, n):# 注意:循环区间 lo, hi =0, i -1while lo < hi: s = A[lo]+ A[hi]if s > A[i]: cnt += hi - lo hi -=1else: lo +=1return cnt
给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。
示例:
输入: [0,1,0,2,1,0,1,3,2,1,2,1]
输出: 6
思路 1
一个简单的方法是遍历两次数组,分别记录每个位置左侧的最高点和右侧的最低点
C++
class Solution {
public:
int trap(vector<int>& H) {
int n = H.size();
vector<int> l_max(H);
vector<int> r_max(H);
for(int i=1; i<n; i++)
l_max[i] = max(l_max[i-1], l_max[i]);
for(int i=n-2; i>=0; i--)
r_max[i] = max(r_max[i+1], r_max[i]);
int ret = 0;
for (int i=1; i<n-1; i++)
ret += min(l_max[i], r_max[i]) - H[i];
return ret;
}
};
思路 2
双指针,遍历一次数组
Python
classSolution:deftrap(self,A):""" :type A: List[int] :rtype: int """ n =len(A) l, r =0, n -1 ans =0 max_l = max_r =0while l <= r:if A[l]<= A[r]:if A[l]> max_l: max_l = A[l]else: ans += max_l - A[l] l +=1else:if A[r]> max_r: max_r = A[r]else: ans += max_r - A[r] r -=1return ans
给定 n 个非负整数 a1,a2,...,an,每个数代表坐标中的一个点 (i, ai) 。在坐标内画 n 条垂直线,垂直线 i 的两个端点分别为 (i, ai) 和 (i, 0)。找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。
说明:你不能倾斜容器,且 n 的值至少为 2。
示例:
输入: [1,8,6,2,5,4,8,3,7]
输出: 49
思路
首尾双指针
Python
classSolution:defmaxArea(self,A):""" :type A: List[int] :rtype: int """ n =len(A) l, r =0, n -1 res = (r - l) *min(A[l], A[r])while l < r:if A[l]< A[r]: l +=1else: r -=1 tmp = (r - l) *min(A[l], A[r]) res =max(res, tmp)return res
编写一个函数,其作用是将输入的字符串反转过来。
示例 1:
输入: "hello"
输出: "olleh"
示例 2:
输入: "A man, a plan, a canal: Panama"
输出: "amanaP :lanac a ,nalp a ,nam A"
思路
首尾双指针
Python
classSolution:defreverseString(self,s):""" :type s: str :rtype: str """ n =len(s) s =list(s)# python 不支持直接修改字符串中的字符 l, r =0, n -1while l < r: s[l], s[r]= s[r], s[l]# swap l +=1 r -=1return''.join(s)
classSolution:defsortColors(self,A):""" :type A: List[int] :rtype: void Do not return anything, modify A in-place instead. """ n =len(A) l =0# l 指示最后一个 0 r = n -1# r 指示第一个 2 i =0while i <= r:if A[i]==0: A[i]= A[l] A[l]=0# 确定最后一个 0 l +=1if A[i]==2: A[i]= A[r] A[r]=2# 确定第一个 2 r -=1 i -=1# 注意回退,因为不确定原 A[r] 处是什么 i +=1
classSolution:deflongestMountain(self,A):""" :type A: List[int] :rtype: int """ n =len(A) res =0 i =1while i < n: l = i -1# 左山脚,注意 i 是从 1 开始的while i < n and A[i]> A[i -1]: i +=1if l == i -1:# 不是山坡 i +=1continue r = i -1# 右山脚while r < n -1and A[r]> A[r +1]: r +=1if r == i -1:# 不是山坡 i +=1continueelse: res =max(res, r - l +1) i = r +1# return res
给定一个字符串 S 和一个字符串 T,请在 S 中找出包含 T 所有字母的最小子串。
示例:
输入: S = "ADOBECODEBANC", T = "ABC"
输出: "BANC"
说明:
如果 S 中不存这样的子串,则返回空字符串 ""。
如果 S 中存在这样的子串,我们保证它是唯一的答案。
思路
同向双指针 + HaspMap
Python
from collections import CounterclassSolution:defminWindow(self,s,t):""" :type s: str :type t: str :rtype: str """ map_t =Counter(t)# 记录每个字符出现的次数 found =dict()# 保存滑动窗口 [i,j] 中出现的符号及其次数 cnt_found =0# 记录已经匹配的数量 min_len =len(s)+1# 记录最短结果 res ="" l =0for r inrange(len(s)):if s[r]in map_t: found[s[r]]= found.get(s[r], 0)+1if found[s[r]]<= map_t[s[r]]: cnt_found +=1if cnt_found >=len(t):# 如果存在这样的字串while (s[l]notin map_t) or (s[l]in found and found[s[l]]> map_t[s[l]]):if s[l]in found and found[s[l]]> map_t[s[l]]: found[s[l]]-=1 l +=1if r - l +1< min_len:# 更新最小结果 min_len = r - l +1 res = s[l: l + min_len]# 等价于 s[l: r+1]return res
给定一个含有 n 个正整数的数组和一个正整数 s ,找出该数组中满足其和 ≥ s 的长度最小的连续子数组。如果不存在符合条件的连续子数组,返回 0。
示例:
输入: s = 7, nums = [2,3,1,2,4,3]
输出: 2
解释: 子数组 [4,3] 是该条件下的长度最小的连续子数组。
进阶: 如果你已经完成了O(n) 时间复杂度的解法, 请尝试 O(n log n) 时间复杂度的解法。
思路
同向双指针
Python
classSolution:defminSubArrayLen(self,s,A):""" :type s: int :type A: List[int] :rtype: int """ n =len(A) res = n +1 l =-1 cur_sum =0for r inrange(n):if A[r]> s:return1 cur_sum += A[r]if cur_sum >= s:while cur_sum >= s:# 注意要使用 >= l +=1# 因为 l 初始化为 -1,所以要先 ++ cur_sum -= A[l] res =min(res, r - l +1)return res if res != n +1else0# 结果不存在时返回 0
无重复字符的最长子串(Longest Substring Without Repeating Characters)
classSolution:deflengthOfLongestSubstring(self,s):""" :type s: str :rtype: int """ n =len(s) res =0 bok =dict() l, r =0,0while r < n:if s[r]notin bok: bok[s[r]]= relse: l =max(l, bok[s[r]] +1)# ERR: l = bok[s[r]] + 1 bok[s[r]]= r res =max(res, r - l +1)# print(res, '\t', r, l) r +=1return res
classSolution:deftotalFruit(self,T):""" :type T: List[int] :rtype: int """ n =len(T) l, r =0,0 res =0 q = [] # 模拟容量为 2 的队列 t =dict()# 记录每个种类最后出现的位置while r < n: t[T[r]]= r # 更新位置if T[r]in q and q[-1]== T[r]:passelif T[r]in q and q[0]== T[r]: q.pop(0) q.append(T[r])eliflen(q)<2and T[r]notin q: q.append(T[r])eliflen(q)>=2and T[r]notin q: l = t[q.pop(0)]+1 q.append(T[r]) res =max(res, r - l +1)# print(res, '\t', l, r) r +=1return res
classSolution:deflongestMountain(self,A):""" :type A: List[int] :rtype: int """ n =len(A) res =0 i =1while i < n -1:# for i in range(1, n - 1):if A[i -1]< A[i]> A[i +1]:# 先找“山峰” l = i -1 r = i +1while l >0and A[l -1]< A[l]:# 找左侧山脚(回溯) l -=1while r < n -1and A[r +1]< A[r]:# 找右侧山脚 r +=1 res =max(res, r - l +1) i = r +1# 跳过右边的下坡,这一段一定不存在山脉else: i +=1return res
classSolution:deflongestPalindrome(self,s):""" :type s: str :rtype: str """ifnot s:return"" self.b, self.l =0,0# begin, length n =len(s)for mid inrange(n): self.foo(s, mid, mid)# 奇数情况 self.foo(s, mid, mid +1)# 偶数的情况return s[self.b: self.b + self.l]deffoo(self,s,l,r): n =len(s)while l >=0and r < n and s[l]== s[r]: l -=1 r +=1if r - l -1> self.l:# 注意这里是 r-l-1,因为退出循环时 s[l] != s[r] self.b = l +1 self.l = r - l -1
classSolution:defstrStr(self,S,T):""" :type S: str :type T: str :rtype: int """ifnot T:# 如果 T 为空,返回 0,与 C++/Java 行为一致return0 n =len(S) m =len(T) ans =-1# 不存在返回 -1 found =0for i inrange(n - m +1):for j inrange(m):if S[i + j]!= T[j]:breakif j == m -1: ans = i found =1if found:breakreturn ans
classSolution:defintersection(self,A,B):""" :type A: List[int] :type B: List[int] :rtype: List[int] """ A.sort() B.sort() m =len(A) n =len(B) res = [] i, j =0,0while i < m and j < n:if A[i]< B[j]: i +=1elif A[i]> B[j]: j +=1else:if (i >0and A[i -1]== A[i]) or (j >0and B[j -1]== B[j]):# 去重passelse: res.append(A[i]) i +=1 j +=1# i += 1# while i < m and A[i - 1] == A[i]:# i += 1# j += 1# while j < n and B[j - 1] == B[j]:# j += 1return res
classSolution:defintersect(self,A,B):""" :type A: List[int] :type B: List[int] :rtype: List[int] """ A.sort() B.sort() m =len(A) n =len(B) res = [] l, r =0,0while l < m and r < n:if A[l]< B[r]: l +=1elif B[r]< A[l]: r +=1else: res.append(A[l]) l +=1 r +=1return res
classSolution:defmerge(self,A,m,B,n):""" :type A: List[int] :type m: int :type B: List[int] :type n: int :rtype: void Do not return anything, modify A in-place instead. """ i = m -1# 指向 A 的末尾 j = n -1# 指向 B 的末尾 p = m + n -1# 指向总的末尾while i >=0and j >=0:# 注意结束条件if A[i]> B[j]: A[p]= A[i] p -=1 i -=1else: A[p]= B[j] p -=1 j -=1while j >=0:# 如果原 A 数组先排完,需要继续把 B 中的元素放进 A;如果 B 先排完,则不需要 A[p]= B[j] p -=1 j -=1
给定一个链表和一个特定值 x,对链表进行分隔,使得所有小于 x 的节点都在大于或等于 x 的节点之前。
你应当保留两个分区中每个节点的初始相对位置。
示例:
输入: head = 1->4->3->2->5->2, x = 3
输出: 1->2->2->4->3->5
思路
链表快排的中间操作;
新建两个链表,分别保存小于 x 和大于等于 x 的,最后拼接;
因为要求节点的相对位置不变,所以这么写比较方便;
一般来说,链表快排有两种写法:一种是交换节点内的值,一种是交换节点;该写法适用于后者。
如果是用在链表快排中,可以把头节点作为 x,最后把 x 插进 lo 和 hi 链表的中间;
这种写法不适合用在链表快排中,因为这里有拼接操作;
在实际链表快排中 partition 操作只对中间一部分执行,如果需要拼接,容易出错。
Python
# Definition for singly-linked list.# class ListNode:# def __init__(self, x):# self.val = x# self.next = NoneclassSolution:defpartition(self,h,x):""" :type h: ListNode :type x: int :rtype: ListNode """ l = lo =ListNode(0) r = hi =ListNode(0)while h:if h.val < x: l.next = h # Python 中不支持 l = l.next = h 的写法,C++ 指针可以 l = l.nextelse: r.next = h # Python 中不支持 r = r.next = h 的写法,C++ 指针可以 r = r.next h = h.next r.next =None# 因为尾节点可能不小于 x,所以需要断开 l.next = hi.nextreturn lo.next
class Solution: def smallestRange(self, A): """ :type A: List[List[int]] :rtype: List[int] """ pq = [(row[0], i, 0) for i, row in enumerate(A)] heapq.heapify(pq) # 最小堆
ans = -1e5, 1e5
r = max(row[0] for row in A)
while pq:
l, i, j = heapq.heappop(pq)
if r - l < ans[1] - ans[0]:
ans = l, r
if j + 1 == len(A[i]):
break
r = max(r, A[i][j+1])
heapq.heappush(pq, (A[i][j+1], i, j+1))
return ans