这个地方主要记载我刷LeetCode时的疑惑和解法,方便自己的总结整理,也希望能给广大网友带来帮助。

3. Longest Substring Without Repeating Characters

Given a string, find the length of the longest substring without repeating characters.

Examples:
Given “abcabcbb”, the answer is “abc”, which the length is 3.
Given “bbbbb”, the answer is “b”, with the length of 1.
Given “pwwkew”, the answer is “wke”, with the length of 3. Note that the answer must be a substring, “pwke” is a subsequence and not a substring.

这道题有点儿像小米面试中的『摘要算法』那道题,也是用两个指针在字符串上去滑动。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Solution(object):
def lengthOfLongestSubstring(self, s):
"""
:type s: str
:rtype: int
"""
res, n = 0, len(s)
if n == 0:
return 0
elif n == 1:
return 1
index1, index2 = 0, 1
while index1 < n and index2 < n:
if s[index2] not in s[index1:index2]:
index2 += 1
res = index2-index1 if index2-index1>res else res
else:
index1 = s[index1:index2].index(s[index2]) + index1 + 1
return res

5. Longest Palindromic Substring

Given a string s, find the longest palindromic substring in s. You may assume that the maximum length of s is 1000.

Example1:

1
2
3
Input: "babad"
Output: "bab"
Note: "aba" is also a valid answer.

Example2:

1
2
Input: "cbbd"
Output: "bb"

定义一个指针i从字符串头部滑到尾部,然后在每一个位置寻找以i为中心的最大回文子串,然后不断更新暂存器中的最大回文子串。

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(object):
def longestPalindrome(self, s):
"""
:type s: str
:rtype: str
"""
size = len(s)
if len(size) == 1:
return s
elif len(size) == 2:
if s[0] == s[1]:
return s
else:
return s[0]
maxp, res, i = 1, s[0], 0
while i < size:
j = i + 1
while j < size:
if s[i] == s[j]:
j += 1
else:
break
k = 0
while i-k-1>=0 and j+k<size:
if s[i-k-1] != s[j+k]:
break
k += 1
if j-i+k*2 > maxp:
maxp = j-i+k*2
res = s[i-k-1:j+k]
if j+k == size-1:
break
i = j
return res

8. String to Integer(atoi)

把空格去掉,然后正负号只能出现在首位

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
class Solution(object):
def myAtoi(self, str):
"""
:type str: str
:rtype: int
"""
str = str.strip()
if len(str) == 0:
return 0
tmp, res, i, n = '0', 0 , 0, len(str)
if str[0] in '+-':
tmp = str[0]
MAX_INT = 2147483647
INT_MIN = -2147483648
for i in xrange(i, n):
if str[i].isdigit():
tmp += str[i]
else:
break
if len(tmp) > 1:
res = int(tmp)
if res > MAX_INT:
return MAX_INT
elif res < INT_MIN:
return INT_MIN
else:
return res

11. Container With Most Water

Given n non-negative integers a1, a2, …, an, where each represents a point at coordinate (i, ai). n vertical lines are drawn such that the two endpoints of line i is at (i, ai) and (i, 0). Find two lines, which together with x-axis forms a container, such that the container contains the most water.

Note: You may not slant the container and n is at least 2.

这道题是说让从n条线里边选两条与x轴构成一个容器,要使容器的容积最大。首先我们要知道容器容积的计算公式应该是两条线中短的那条乘上两条线的距离。直接两层for循环就可以求出来,但是肯定超时了。我们可以从list的两端出发,先选择最左边和最右边一条,然后不断更新两条边中短的一条,直至两条边相遇,此时就得到的最大的容积。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Solution(object):
def maxArea(self, height):
"""
:type height: List[int]
:rtype: int
"""
n = len(height)
if n <= 2:
return min(height)
res = min(height[0], height[-1]) * (n-1)
low, high = 0, n-1
while low < high:
res = max(res, min(height[low], height[high])*(high-low))
if height[low] > height[high]:
high -= 1
else:
low += 1
return res

16. 3Sum Cloest

Given an array S of n integers, find three integers in S such that the sum is closest to a given number, target. Return the sum of the three integers. You may assume that each input would have exactly one solution.

1
2
For example, given array S = {-1 2 1 -4}, and target = 1.
The sum that is closest to the target is 2. (-1 + 2 + 1 = 2).

最直接的做法就是三层for循环,肯定是超时的。想到《剑指offer》中第41题『和为s的两个整数VS和为s的连续正数序列』,我觉得可能需要先对数组进行排序,然后再用移动指针的方法找到答案。后来得到证明,这种方法的确是可行的:首先对数组进行排序,然后在数组中找到不小于target//3的第一个数字所在的位置i。固定i,定义两个指针分别指向数组的头部和尾部,然后逐步向i移动两个指针,得到一个局部最优解。通过移动两个指针求局部最优解的方法见下面的unit函数。考虑到i的位置不是特别准确,因此在i-1、i、i+1三个位置分别执行一个unit函数,求三者的最优解。特殊情况,当i指向数组头部和尾部时,两个滑动指针都位于i的同一侧,因此while循环的条件是index1<index2,我把这种特殊情况写成了unit2函数。

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
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
class Solution(object):
def threeSumClosest(self, nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: int
"""
# 先排序,然后定位到target//3附近位置,然后再找
nums.sort()
tmp, n, i = target//3, len(nums), 0
for i in range(n):
if nums[i] >= tmp:
break
elif nums[i] < tmp:
continue
def unit(nums, target, i):
n = len(nums)
if i == 0:
# return sum(nums[:3])
index1, index2 = 1, n-1
elif i >= n-1:
# return sum(nums[-3:])
index1, index2 = 0, n-2
else:
index1, index2 = 0, n-1
res = sum([nums[index1], nums[index2], nums[i]])
while index1 < i and index2 > i:
tmp = sum([nums[index1], nums[index2], nums[i]])
if tmp == target:
return tmp
elif tmp > target:
if res > target:
res = tmp if res > tmp else res
else:
res = tmp if abs(tmp - target) < abs(target-res) else res
index2 -= 1
elif tmp < target:
if res < target:
res = tmp if res < tmp else res
else:
res = tmp if abs(target-tmp) < abs(res-target) else res
index1 += 1
return res
def unit2(nums, target, i):
n = len(nums)
if i == 0:
# return sum(nums[:3])
index1, index2 = 1, n-1
elif i == n-1:
# return sum(nums[-3:])
index1, index2 = 0, n-2
res = sum([nums[index1], nums[index2], nums[i]])
while index1 < index2:
tmp = sum([nums[index1], nums[index2], nums[i]])
if tmp == target:
return tmp
elif tmp > target:
if res > target:
res = tmp if res > tmp else res
else:
res = tmp if abs(tmp - target) < abs(target-res) else res
index2 -= 1
elif tmp < target:
if res < target:
res = tmp if res < tmp else res
else:
res = tmp if abs(target-tmp) < abs(res-target) else res
index1 += 1
return res
if i == 0:
tmp1, tmp2, tmp3 = unit2(nums, target, i), unit(nums, target, i+1), unit(nums, target, i+2)
elif i >= n-1:
tmp1, tmp2, tmp3 = unit(nums, target, n-3), unit(nums, target, n-2), unit2(nums, target, n-1)
else:
tmp1, tmp2, tmp3 = unit(nums, target, i-1), unit(nums, target, i), unit(nums, target, i+1)
res = tmp1 if abs(tmp1-target) < abs(tmp2-target) else tmp2
res = res if abs(res-target) < abs(tmp3-target) else tmp3
return res
# 最笨的方法,超时
# n = len(nums)
# res = sum(nums[0:3])
# flag = abs(target - res)
# for i in range(0, n-2):
# for j in range(i+1, n-1):
# for k in range(j+1, n):
# tmp = sum([nums[i], nums[j], nums[k]])
# if abs(target - tmp) < flag:
# res, flag = tmp, abs(target-tmp)
# return res

这道题debug了两个多小时,阿衰。

64. Minimum Path Sum

Given a m x n grid filled with non-negative numbers, find a path from top left to bottom right which minimizes the sum of all numbers along its path.

Note: You can only move either down or right at any point in time.

Example 1:

1
2
3
[[1,3,1],
[1,5,1],
[4,2,1]]

Given the above grid map, return 7. Because the path 1→3→1→1→1 minimizes the sum.

DP问题。给定矩阵grid,要求出从左上角到右下角的最小代价,其实只需要计算出从左上角到grid[i][j]的最小代价,然后一直DP到右下角即可。我们要先计算最左侧一列位置和最上面一行位置的代价:对于最左侧一列,只需要把在它上面的数字都加过来就得到了到当前点的最小代价;对于最上面一行,只需要把左侧的代价值都加过来就得到了到当前点的最小代价。然后再求到其它点的最小代价,要到达grid[i][j],要么是从grid[i-1][j]过来,要么是从grid[i][j-1]过来,而到达这两点的最小代价都已经求出来了,因此到达grid[i][j]的最小代价为grid[i][j]+min(grid[i-1][j], grid[i][j-1])。下面是python实现。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Solution:
def minPathSum(self, grid):
"""
:type grid: List[List[int]]
:rtype: int
"""
m, n = len(grid), len(grid[0])
for i in range(1, m):
grid[i][0] += grid[i-1][0]
for i in range(1, n):
grid[0][i] += grid[0][i-1]
for i in range(1, m):
for j in range(1, n):
grid[i][j] += min(grid[i-1][j], grid[i][j-1])
return grid[-1][-1]

121. Best Time to Buy and Sell Stock

Say you have an array for which the ith element is the price of a given stock on day i.

If you were only permitted to complete at most one transaction (ie, buy one and sell one share of the stock), design an algorithm to find the maximum profit.

Example 1:

1
2
3
4
Input: [7, 1, 5, 3, 6, 4]
Output: 5
max. difference = 6-1 = 5 (not 7-1 = 6, as selling price needs to be larger than buying price)

Example 2:

1
2
3
4
Input: [7, 6, 4, 3, 1]
Output: 0
In this case, no transaction is done, i.e. max profit = 0.

DP问题。要求出最大收益的话,我们需要暂存一个到目前为止的最低价minprice和收益res,每过一天就更新一次minprice=min(minprice, prices[i]),然后去求这一天卖出的话收益会不会超过之前的最大收益,超过的话更新res。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Solution(object):
def maxProfit(self, prices):
"""
:type prices: List[int]
:rtype: int
"""
n = len(prices)
if n <= 1:
return 0
res = 0
minprice = prices[0]
for i in range(1, n):
minprice = min(minprice, prices[i])
if prices[i] - minprice > res:
res = prices[i] - minprice
return res

153. Find Minimum in Rotated Sorted Array

Suppose an array sorted in ascending order is rotated at some pivot unknown to you beforehand.

(i.e., 0 1 2 4 5 6 7 might become 4 5 6 7 0 1 2).

Find the minimum element.

You may assume no duplicate exists in the array.

LeetCode原题的简化版。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Solution:
def findMin(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
n = len(nums)
if n <= 2:
return min(nums)
low, high = 0, n-1
if nums[high] > nums[low]:
return nums[low]
while low <= high:
mid = (low+high)//2
if nums[mid] < nums[high]:
high = mid
else:
low = mid + 1
return nums[high]

198. House Robber

You are a professional robber planning to rob houses along a street. Each house has a certain amount of money stashed, the only constraint stopping you from robbing each of them is that adjacent houses have security system connected and it will automatically contact the police if two adjacent houses were broken into on the same night.

Given a list of non-negative integers representing the amount of money of each house, determine the maximum amount of money you can rob tonight without alerting the police.

这道题应该是用动态规划。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Solution(object):
def rob(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
n = len(nums)
if n == 0:
return 0
elif n == 1:
return nums[0]
elif n == 2:
return max(nums)
prev, curr = nums[0], max(nums[0:2])
for i in range(2, n):
res = max(prev+nums[i], curr)
prev, curr = curr, res
return res

300. Longest Increasing Subsequence

Given an unsorted array of integers, find the length of longest increasing subsequence.

For example,
Given [10, 9, 2, 5, 3, 7, 101, 18],
The longest increasing subsequence is [2, 3, 7, 101], therefore the length is 4. Note that there may be more than one LIS combination, it is only necessary for you to return the length.

Your algorithm should run in O(n^2) complexity.

Follow up: Could you improve it to O(n log n) time complexity?

解题思路: tails is an array storing the smallest tail of all increasing subsequences with length i+1 in tails[i]. For example, say we have nums=[4, 5, 6, 3], then all the available increasing subsequences are:

1
2
3
len = 1: [4], [5], [6], [3] => tails[0] = 3
len = 2: [4, 5], [5, 6] => tails[1] = 5
len = 3: [4, 5, 6] => tails[2] = 6

We can easily prove that tails is an increeasing array. Therefore it is possible to do a binary search in tails array to find the one needs update.
Each time we only do one of the two:
1) if x is larger than all tails, append it, increase the size by 1
2) if tails[i-1] < x <= tails[i], update tails[i]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Solution(object):
def lengthOfLIS(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
n = len(nums)
tails = [0] * n
size = 0
for x in nums:
i, j = 0, size
while i != j:
m = (i+j)/2
if tails[m] < x:
i = m+1
else:
j = m
tails[i] = x
size = max(i+1, size)
return size

303. Range Sum Query - Immutable

Given an integer array nums, find the sum of the elements between indices i and j (i ≤ j), inclusive.

Example:

1
2
3
4
5
Given nums = [-2, 0, 3, -5, 2, -1]
sumRange(0, 2) -> 1
sumRange(2, 5) -> -1
sumRange(0, 5) -> -3

Note:

  • You may assume that the array does not change.
  • There are many calls to sumRange function.

DP问题,我们可以用一个数组来存储前k个元素的和。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class NumArray:
def __init__(self, nums):
"""
:type nums: List[int]
"""
self.dp, n = nums, len(nums)
for i in range(1, n):
self.dp[i] += self.dp[i-1]
def sumRange(self, i, j):
"""
:type i: int
:type j: int
:rtype: int
"""
return self.dp[j] - (self.dp[i-1] if i > 0 else 0)
# Your NumArray object will be instantiated and called as such:
# obj = NumArray(nums)
# param_1 = obj.sumRange(i,j)

392. Is Subsequence

Given a string s and a string t, check if s is subsequence of t.

You may assume that there is only lower case English letters in both s and t. t is potentially a very long (length ~= 500,000) string, and s is a short string (<=100).

A subsequence of a string is a new string which is formed from the original string by deleting some (can be none) of the characters without disturbing the relative positions of the remaining characters. (ie, “ace” is a subsequence of “abcde” while “aec” is not).

Example 1:

1
2
3
s = "abc", t = "ahbgdc"
Return true.

Example 2:

1
2
3
s = "axc", t = "ahbgdc"
Return false.

Follow up:
If there are lots of incoming S, say S1, S2, … , Sk where k >= 1B, and you want to check one by one to see if T has its subsequence. In this scenario, how would you change your code?

直接用两个指针分别去遍历两个字符串即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Solution:
def isSubsequence(self, s, t):
"""
:type s: str
:type t: str
:rtype: bool
"""
lens, lent = len(s), len(t)
index1, index2 = 0, 0
while index1 < lens and index2 < lent:
if s[index1] == t[index2]:
index1 += 1
index2 += 1
else:
index2 += 1
if index1 == lens:
return True
else:
return False

416. Partition Equal Subset Sum

Given a non-empty array containing only positive integers, find if the array can be partitioned into two subsets such that the sum of elements in both subsets is equal.

Note:

  • Each of the array element will not exceed 100.
  • The array size will not exceed 200.

Example 1:

1
2
3
4
5
Input: [1, 5, 11, 5]
Output: true
Explanation: The array can be partitioned as [1, 5, 5] and [11].

Example 2:

1
2
3
4
5
Input: [1, 2, 3, 5]
Output: false
Explanation: The array cannot be partitioned into equal sum subsets.

题设要求将数组分成两半,然后判断两个子数组的和是否相等。由于数组中数字全是正的,因此数组长度必定为偶数。我们可以将这个问题转换成一个背包问题,即从数组中拿出一半的元素,其和能不能是整个数组的和的一半。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Solution(object):
def canPartition(self, nums):
"""
:type nums: List[int]
:rtype: bool
"""
half_sum, n = sum(nums), len(nums)
if half_sum % 2 == 1:
return False
half_sum /= 2
d = [[False for x in range(half_sum+1)] for y in range(n+1)]
for k in range(n+1):
d[k][0] = True
for i in range(1, n+1):
for j in range(0, half_sum+1):
d[i][j] = d[i-1][j]
if j >= nums[i-1]:
d[i][j] = d[i][j] | d[i-1][j-nums[i-1]]
print(d)
return d[len(nums)][half_sum]

646. Maximum Length of Pair Chain

You are given n pairs of numbers. In every pair, the first number is always smaller than the second number.

Now, we define a pair (c, d) can follow another pair (a, b) if and only if b < c. Chain of pairs can be formed in this fashion.

Given a set of pairs, find the length longest chain which can be formed. You needn’t use up all the given pairs. You can select pairs in any order.

Example 1:

1
2
3
Input: [[1,2], [2,3], [3,4]]
Output: 2
Explanation: The longest chain is [1,2] -> [3,4]

Note:

  • The number of given pairs will be in the range [1, 1000].

DP问题,下面是三种解法,后两种是一样的,只用一层for循环;第一种用了两层for循环,结果超时。

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
class Solution:
def findLongestChain(self, pairs):
"""
:type pairs: List[List[int]]
:rtype: int
"""
# 两层for循环的DP操作超时
n = len(pairs)
pairs = sorted(pairs, key=lambda x: x[0])
res = [1] * n
for i in range(n-1, -1, -1):
for j in range(i+1, n):
if pairs[i][1] < pairs[j][0]:
res[i] = max(res[i], res[j] + 1)
else:
res[i] = max(res[i], res[j])
return max(res)
def findLongestChain2(self, pairs):
"""
:type pairs: List[List[int]]
:rtype: int
"""
cur, res, n= float('inf'), 0, len(pairs)
pairs = sorted(pairs, key=lambda x: x[0])
for i in range(n-1, -1, -1):
if cur > pairs[i][1]:
cur, res = pairs[i][0], res + 1
return res
def findLongestChain3(self, pairs):
"""
:type pairs: List[List[int]]
:rtype: int
"""
cur, res = float('-inf'), 0
pairs = sorted(pairs, key=lambda x: x[1])
for p in pairs:
if cur < p[0]:
cur, res = p[1], res + 1
return res

740. Delete and Earn

Given an array nums of integers, you can perform operations on the array.

In each operation, you pick any nums[i] and delete it to earn nums[i] points. After, you must delete every element equal to nums[i] - 1 or nums[i] + 1.

You start with 0 points. Return the maximum number of points you can earn by applying such operations.

Example 1:

1
2
3
4
5
Input: nums = [3, 4, 2]
Output: 6
Explanation:
Delete 4 to earn 4 points, consequently 3 is also deleted.
Then, delete 2 to earn 2 points. 6 total points are earned.

Example 2:

1
2
3
4
5
6
Input: nums = [2, 2, 3, 3, 3, 4]
Output: 9
Explanation:
Delete 3 to earn 3 points, deleting both 2's and the 4.
Then, delete 3 again to earn 3 points, and 3 again to earn 3 points.
9 total points are earned.

Note:

  • The length of nums is at most 20000.
  • Each element nums[i] is an integer in the range [1, 10000].

这道题是198题House Robber问题的升级版:我们可以定义一个长度为10001的数组values(因为限制了nums中的数字在[1, 10000]之间),数字num在nums中出现k次,则执行k次values[num] += num。因为题设中说取了num,就不能取num-1和num+1,现在就转化成了取了values[num]就不能取values[num-1]和values[num+1],此时已经完全转换成198题了,使用DP就可以解决了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Solution(object):
def deleteAndEarn(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
values = [0] * 10001
for num in nums:
values[num] += num
prev, curr = 0, 0
for value in values:
prev, curr = curr, max(prev+value, curr)
return curr

746. Min Cost Climbing Stairs

On a staircase, the i-th step has some non-negative cost cost[i] assigned (0 indexed).

Once you pay the cost, you can either climb one or two steps. You need to find minimum cost to reach the top of the floor, and you can either start from the step with index 0, or the step with index 1.

Example 1:

1
2
3
**Input:** cost = [10, 15, 20]
**Output:** 15
**Explanation:** Cheapest is start on cost[1], pay that cost and go to the top.

Example 2:

1
2
3
**Input**: cost = [1, 100, 1, 1, 1, 100, 1, 1, 100, 1]
**Output**: 6
**Explanation**: Cheapest is start on cost[0], and only step on 1s, skipping cost[3].

Note:

  • cost will have a length in the range [2, 1000].
  • Every cost[i] will be an integer in the range [0, 999].

DP问题。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Solution(object):
def minCostClimbingStairs(self, cost):
"""
:type cost: List[int]
:rtype: int
"""
n = len(cost)
if n == 1:
return cost[0]
elif n == 2:
return min(cost)
tmp1, tmp2 = cost[0], cost[1]
for i in range(2, n):
tmp1, tmp2 = tmp2, min(tmp1+cost[i], tmp2+cost[i])
return min(tmp1, tmp2)