LeetCode 编程
1. Two Sum
Given an array of integers, return indices of the two numbers such that they add up to a specific target.
You may assume that each input would have exactly one solution, and you may not use the same element twice.
- Example:
Given nums = [2, 7, 11, 15], target = 9,
Because nums[0] + nums[1] = 2 + 7 = 9,
return [0, 1].
- code:
class Solution {
public: // 要么用 map,要么用排序
vector<int> twoSum(vector<int>& nums, int target) {
if(nums.size() <= 0) {
return vector<int>({-1, -1});
}
std::map<int, int> compliments;
// 成对出现,一次循环
for(int i=0; i<nums.size(); ++i) {
std::map<int, int>::iterator it = compliments.find(nums[i]);
if(it != compliments.end()) {
return vector<int>({it->second, i});
}
compliments.emplace(target - nums[i], i);
}
return vector<int>({-1, -1});
}
};
2. Add Two Numbers
You are given two non-empty linked lists representing two non-negative integers. The digits are stored in reverse order and each of their nodes contain a single digit. Add the two numbers and return it as a linked list.
You may assume the two numbers do not contain any leading zero, except the number 0 itself.
- Example:
Input: (2 -> 4 -> 3) + (5 -> 6 -> 4)
Output: 7 -> 0 -> 8
Explanation: 342 + 465 = 807.
- code:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* addTwoNumbers(ListNode* l1, ListNode*l2) {
ListNode result(0); //初始换链表
ListNode* iter = &result; //指针iter指向result的地址
int carry = 0;
// 指针为空
while (l1 || l2 || carry) {
int sum = carry + (l1 ? l1->val : 0) + (l2 ? l2->val : 0);
carry = sum / 10;
iter->next = new ListNode(sum % 10);
iter = iter->next;
l1 ? l1 = l1->next:0;
l2 ? l2 = l2->next:0;
}
return result.next;
}
};
3. Longest Substring Without Repeating Characters !!!
Given a string, find the length of the longest substring without repeating characters.
- Example:
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.
- code:
/*
* 遍历 string,记住 start,记录每个字符最后一次出现的 index,
* 如果 index 大于 start,则出现重复了,因为 index 是递增的。重复了就更新 start
*/
class Solution {
public:
int lengthOfLongestSubstring(string s) {
if (s.empty()) {
return 0;
}
// 有明显限制的元素,数组就可以当 map
vector<int> last_seen_idx(128, -1); // 存放每个字符最后出现 index
// 字符串开始 end 字符串结束
int start = 0;
last_seen_idx[s[0]] = 0;
int res = 1;
for (int end = 1; end < s.size(); ++end) {
auto c = s[end];
// 出现一次,对应字符上的 last_seen_idx + 1;如果有last_seen_idx[c] >= start :
// 说明有重复的了!!!
if (last_seen_idx[c] < start) {
if (end - start + 1 > res) {
res = end - start + 1;
}
} else {
start = last_seen_idx[c] + 1;
}
last_seen_idx[c] = end;
}
return res;
}
};
4. Median of Two Sorted Arrays !!!
There are two sorted arrays nums1 and nums2 of size m and n respectively.
Find the median of the two sorted arrays. The overall run time complexity should be O(log (m+n)).
You may assume nums1 and nums2 cannot be both empty.
- Example:
nums1 = [1, 3]
nums2 = [2]
The median is 2.0
nums1 = [1, 2]
nums2 = [3, 4]
The median is (2 + 3)/2 = 2.5
- code:
class Solution {
public:
int getKthElement(const vector<int>& nums1, const vector<int>& nums2, int k) {
/* 主要思路:要找到第 k (k>1) 小的元素,那么就取 pivot1 = nums1[k/2-1] 和 pivot2 = nums2[k/2-1] 进行比较
* 这里的 "/" 表示整除
* nums1 中小于等于 pivot1 的元素有 nums1[0 .. k/2-2] 共计 k/2-1 个
* nums2 中小于等于 pivot2 的元素有 nums2[0 .. k/2-2] 共计 k/2-1 个
* 取 pivot = min(pivot1, pivot2),两个数组中小于等于 pivot 的元素共计不会超过 (k/2-1) + (k/2-1) <= k-2 个
* 这样 pivot 本身最大也只能是第 k-1 小的元素
* 如果 pivot = pivot1,那么 nums1[0 .. k/2-1] 都不可能是第 k 小的元素。把这些元素全部 "删除",剩下的作为新的 nums1 数组
* 如果 pivot = pivot2,那么 nums2[0 .. k/2-1] 都不可能是第 k 小的元素。把这些元素全部 "删除",剩下的作为新的 nums2 数组
* 由于我们 "删除" 了一些元素(这些元素都比第 k 小的元素要小),因此需要修改 k 的值,减去删除的数的个数
*/
int m = nums1.size();
int n = nums2.size();
int index1 = 0, index2 = 0;
while (true) {
// 边界情况
if (index1 == m) {
return nums2[index2 + k - 1];
}
if (index2 == n) {
return nums1[index1 + k - 1];
}
if (k == 1) {
return min(nums1[index1], nums2[index2]);
}
// 正常情况
int newIndex1 = min(index1 + k / 2 - 1, m - 1);
int newIndex2 = min(index2 + k / 2 - 1, n - 1);
int pivot1 = nums1[newIndex1];
int pivot2 = nums2[newIndex2];
if (pivot1 <= pivot2) {
k -= newIndex1 - index1 + 1;
index1 = newIndex1 + 1;
} else {
k -= newIndex2 - index2 + 1;
index2 = newIndex2 + 1;
}
}
}
double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
int totalLength = nums1.size() + nums2.size();
if (totalLength % 2 == 1) {
return getKthElement(nums1, nums2, (totalLength + 1) / 2);
}
else {
return (getKthElement(nums1, nums2, totalLength / 2) + getKthElement(nums1, nums2, totalLength / 2 + 1)) / 2.0;
}
}
};
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.
- Example:
Input: "babad"
Output: "bab"
Note: "aba" is also a valid answer.
Input: "cbbd"
Output: "bb"
- 动态规划思路与算法
对于一个子串而言,如果它是回文串,并且长度大于 2,那么将它首尾的两个字母去除之后,它仍然是个回文串。例如对于字符串
“ababa”,如果我们已经知道 “bab” 是回文串,那么 “ababa” 一定是回文串,这是因为它的首尾两个字母都是 “a”。根据这样的思路,我们就可以用动态规划的方法解决本题。我们用 P(i,j) 表示字符串 S 第 i 到 j 个字母组成的串(下文用 s[i:j])是否为回文串:
P ( i , j ) = { t r u e , 如 果 子 串 S i . . . S j 是 回 文 串 f a l s e , 其 他 情 况 P(i,j) = \begin{cases} true, &如果子串 S_i...S_j是回文串\\ false, &其他情况 \end{cases} P(i,j)={true,false,如果子串Si...Sj是回文串其他情况
这里的「其它情况」包含两种可能:
- s[i:j] 本身不是回文串
- i > j 这时候 s[i:j] 不合法
那么我们就可以写出动态规划的状态转移方程:
P ( i , j ) = P ( i + 1 , j − 1 ) ∧ ( S i = = S j ) P(i,j) = P(i+1,j-1) ∧ (S_i == Sj) P(i,j)=P(i+1,j−1)∧(Si==Sj)
也就是说,只有 s[i+1:j-1] 是回文串,并且 s 的第 i 和 j 个字母相同时,s[i:j] 才会是回文串。
上文的所有讨论是建立在子串长度大于 2 的前提之上的,我们还需要考虑动态规划中的边界条件,即子串的长度为 1 或 2。对于长度为 1 的子串,它显然是个回文串;对于长度为 2 的子串,只要它的两个字母相同,它就是一个回文串。因此我们就可以写出动态规划的边界条件:
{ P ( i , i ) = t r u e P ( i , i + 1 ) = ( S i = = S i + 1 ) \begin{cases} P(i,i) = true\\ P(i,i+1) = (S_i == S_{i+1}) \end{cases} {P(i,i)=trueP(i,i+1)=(Si==Si+1)
根据这个思路,我们就可以完成动态规划了,最终的答案即为所有 P(i,j) = true 中 j−i+1(即子串长度)的最大值。注意:在状态转移方程中,我们是从长度较短的字符串向长度较长的字符串进行转移的,因此一定要注意动态规划的循环顺序。
- code:
class Solution {
public:
// 动态规划
string longestPalindrome(string s) {
int n = s.size();
vector<vector<int>> dp(n, vector<int>(n));
string ans;
for (int l = 0; l < n; ++l) {
for (int i = 0; i + l < n; ++i) {
int j = i + l;
if (l == 0) {
dp[i][j] = 1;
} else if (l == 1) {
dp[i][j] = (s[i] == s[j]);
} else {
dp[i][j] = (s[i] == s[j] && dp[i + 1][j - 1]);
}
if (dp[i][j] && l + 1 > ans.size()) {
ans = s.substr(i, l + 1);
}
}
}
return ans;
}
};
6. ZigZag Conversion
The string “PAYPALISHIRING” is written in a zigzag pattern on a given number of rows like this: (you may want to display this pattern in a fixed font for better legibility)
P A H N
A P L S I I G
Y I R
And then read line by line: “PAHNAPLSIIGYIR”
Write the code that will take a string and make this conversion given a number of rows:
string convert(string s, int numRows);
- Example:
Input: s = "PAYPALISHIRING", numRows = 3
Output: "PAHNAPLSIIGYIR"
Input: s = "PAYPALISHIRING", numRows = 4
Output: "PINALSIGYAHRPI"
Explanation:
P I N
A L S I G
Y A H R
P I
- code:
class Solution {
public:
string convert(string s, int numRows) {
if (numRows == 1) return s;
vector<string> rows(min(numRows, int(s.size())));
int curRow = 0;
bool goingDown = false;
for (char c : s) {
rows[curRow] += c;
if (curRow == 0 || curRow == numRows - 1) goingDown = !goingDown;
curRow += goingDown ? 1 : -1;
}
string ret;
for (string row : rows) ret += row;
return ret;
}
};
7. Reverse Integer
Given a 32-bit signed integer, reverse digits of an integer.
- Example:
Input: 123
Output: 321
Input: -123
Output: -321
Input: 120
Output: 21
- code:
class Solution {
public:
int reverse(int x) {
int rev = 0;
while (x != 0) {
int pop = x % 10;
x /= 10;
if (rev > INT_MAX/10 || (rev == INT_MAX / 10 && pop > 7)) return 0;
if (rev < INT_MIN/10 || (rev == INT_MIN / 10 && pop < -8)) return 0;
rev = rev * 10 + pop;
}
return rev;
}
};
8. String to Integer (atoi)
Implement atoi which converts a string to an integer.
The function first discards as many whitespace characters as necessary until the first non-whitespace character is found. Then, starting from this character, takes an optional initial plus or minus sign followed by as many numerical digits as possible, and interprets them as a numerical value.
The string can contain additional characters after those that form the integral number, which are ignored and have no effect on the behavior of this function.
If the first sequence of non-whitespace characters in str is not a valid integral number, or if no such sequence exists because either str is empty or it contains only whitespace characters, no conversion is performed.
If no valid conversion could be performed, a zero value is returned.
- Example:
Input: "42"
Output: 42
Input: " -42"
Output: -42
Explanation: The first non-whitespace character is '-', which is the minus sign.Then take as many numerical digits as possible, which gets 42.
Input: "4193 with words"
Output: 4193
Explanation: Conversion stops at digit '3' as the next character is not a numerical digit.
Input: "words and 987"
Output: 0
Explanation: The first non-whitespace character is 'w', which is not a numerical digit or a +/- sign. Therefore no valid conversion could be performed.
Input: "-91283472332"
Output: -2147483648
Explanation: The number "-91283472332" is out of the range of a 32-bit signed integer. Thefore INT_MIN (−231) is returned.
- code:
class Automaton {
string state = "start";
unordered_map<string, vector<string>> table = {
{"start", {"start", "signed", "in_number", "end"}},
{"signed", {"end", "end", "in_number", "end"}},
{"in_number", {"end", "end", "in_number", "end"}},
{"end", {"end", "end", "end", "end"}}
};
int get_col(char c) {
if (isspace(c)) return 0;
if (c == '+' or c == '-') return 1;
if (isdigit(c)) return 2;
return 3;
}
public:
int sign = 1;
long long ans = 0;
void get(char c) {
state = table[state][get_col(c)];
if (state == "in_number") {
ans = ans * 10 + c - '0';
ans = sign == 1 ? min(ans, (long long)INT_MAX) : min(ans, -(long long)INT_MIN);
} else if (state == "signed") {
sign = c == '+' ? 1 : -1;
}
}
};
class Solution {
public:
int myAtoi(string str) {
Automaton automaton;
for (char c : str)
automaton.get(c);
return automaton.sign * automaton.ans;
}
};
9. Palindrome Number
Determine whether an integer is a palindrome. An integer is a palindrome when it reads the same backward as forward.
- Example:
Input: 121
Output: true
Input: -121
Output: false
Explanation: From left to right, it reads -121. From right to left, it becomes 121-. Therefore it is not a palindrome.
Input: 10
Output: false
Explanation: Reads 01 from right to left. Therefore it is not a palindrome.
- code:
class Solution {
public:
bool isPalindrome(int x) {
// 特殊情况:
// 如上所述,当 x < 0 时,x 不是回文数。
// 同样地,如果数字的最后一位是 0,为了使该数字为回文,
// 则其第一位数字也应该是 0
// 只有 0 满足这一属性
if (x < 0 || (x % 10 == 0 && x != 0)) {
return false;
}
int revertedNumber = 0;
while (x > revertedNumber) {
revertedNumber = revertedNumber * 10 + x % 10;
x /= 10;
}
// 当数字长度为奇数时,我们可以通过 revertedNumber/10 去除处于中位的数字。
// 例如,当输入为 12321 时,在 while 循环的末尾我们可以得到 x = 12,revertedNumber = 123,
// 由于处于中位的数字不影响回文(它总是与自己相等),所以我们可以简单地将其去除。
return x == revertedNumber || x == revertedNumber / 10;
}
};
10. Regular Expression Matching !!!
Given an input string (s) and a pattern §, implement regular expression matching with support for ‘.’ and ‘*’.
- Example:
Input:
s = "aa"
p = "a"
Output: false
Explanation: "a" does not match the entire string "aa".
Input:
s = "aa"
p = "a*"
Output: true
Explanation: '*' means zero or more of the precedeng element, 'a'. Therefore, by repeating 'a' once, it becomes "aa".
Input:
s = "ab"
p = ".*"
Output: true
Explanation: ".*" means "zero or more (*) of any character (.)".
Input:
s = "aab"
p = "c*a*b"
Output: true
Explanation: c can be repeated 0 times, a can be repeated 1 time. Therefore it matches "aab".
Input:
s = "mississippi"
p = "mis*is*p*."
Output: false
- 动态规划思路
p[0:i] 能否实现 s[0:i],i 递增;p[0:i+1] 能否实现 s[0:i],i 递增;二维数组
- code:
class Solution {
public:
bool isMatch(string s, string p) {
int m = s.size();
int n = p.size();
auto matches = [&](int i, int j) {
if (i == 0) {
return false;
}
if (p[j - 1] == '.') {
return true;
}
return s[i - 1] == p[j - 1];
};
vector<vector<int>> f(m + 1, vector<int>(n + 1));
f[0][0] = true;
for (int i = 0; i <= m; ++i) {
for (int j = 1; j <= n; ++j) {
if (p[j - 1] == '*') {
f[i][j] |= f[i][j - 2];
if (matches(i, j - 1)) {
f[i][j] |= f[i - 1][j];
}
} else {
if (matches(i, j)) {
f[i][j] |= f[i - 1][j - 1];
}
}
}
}
return f[m][n];
}
};
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.
![LeetCode1](https://i-blog.csdnimg.cn/blog_migrate/a79409349b3caee9f308ef53d7814add.png)
- Example:
Input: [1,8,6,2,5,4,8,3,7]
Output: 49
- 思路
双指针往里夹,移动高度较小的指针
- code:
class Solution {
public:
int maxArea(vector<int>& height) {
int l = 0, r = height.size() - 1;
int ans = 0;
while (l < r) {
int area = min(height[l], height[r]) * (r - l);
ans = max(ans, area);
if (height[l] <= height[r]) {
++l;
} else {
--r;
}
}
return ans;
}
};
12. Integer to Roman
Roman numerals are represented by seven different symbols: I, V, X, L, C, D and M.
Symbol Value
I 1
V 5
X 10
L 50
C 100
D 500
M 1000
- Example:
Input: 3
Output: "III"
Input: 4
Output: "IV"
Input: 9
Output: "IX"
Input: 58
Output: "LVIII"
Explanation: C = 100, L = 50, XXX = 30 and III = 3.
Input: 1994
Output: "MCMXCIV"
Explanation: M = 1000, CM = 900, XC = 90 and IV = 4.
- code:
digits = [(1000, "M"), (900, "CM"), (500, "D"), (400, "CD"), (100, "C"), (90, "XC"),
(50, "L"), (40, "XL"), (10, "X"), (9, "IX"), (5, "V"), (4, "IV"), (1, "I")]
def intToRoman(self, num: int) -> str:
roman_digits = []
# Loop through each symbol.
for value, symbol in digits:
# We don't want to continue looping if we're done.
if num == 0: break
count, num = divmod(num, value)
# Append "count" copies of "symbol" to roman_digits.
roman_digits.append(symbol * count)
return "".join(roman_digits)
13. Roman to Integer
- Example:
Input: "MCMXCIV"
Output: 1994
Explanation: M = 1000, CM = 900, XC = 90 and IV = 4.
- code:
class Solution {
public:
int romanToInt(string s) {
unordered_map<char, int> m;
m['I'] = 1;
m['V'] = 5;
m['X'] = 10;
m['L'] = 50;
m['C'] = 100;
m['D'] = 500;
m['M'] = 1000;
int result = 0;
char prev = 'M';
for (char c : s){
if (m[c] > m[prev]){
result -= 2*m[prev];
}
result += m[c];
prev = c;
}
return result;
}
};
14. Longest Common Prefix
Write a function to find the longest common prefix string amongst an array of strings.
If there is no common prefix, return an empty string “”.
- Example:
Input: ["flower","flow","flight"]
Output: "fl"
Input: ["dog","racecar","car"]
Output: ""
Explanation: There is no common prefix among the input strings.
- code:
class Solution {
public:
string longestCommonPrefix(vector<string>& strs) {
if (!strs.size()) {
return "";
}
string prefix = strs[0];
int count = strs.size();
for (int i = 1; i < count; ++i) {
prefix = longestCommonPrefix(prefix, strs[i]);
if (!prefix.size()) {
break;
}
}
return prefix;
}
string longestCommonPrefix(const string& str1, const string& str2) {
int length = min(str1.size(), str2.size());
int index = 0;
while (index < length && str1[index] == str2[index]) {
++index;
}
return str1.substr(0, index);
}
};
15. 3Sum
Given an array nums of n integers, are there elements a, b, c in nums such that a + b + c = 0? Find all unique triplets in the array which gives the sum of zero.
- Example:
Given array nums = [-1, 0, 1, 2, -1, -4],
A solution set is:
[
[-1, 0, 1],
[-1, -1, 2]
]
- code:
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
int n = nums.size();
// 穷举 O(n^3) 排序忽略不计
sort(nums.begin(), nums.end());
vector<vector<int>> ans;
// 枚举 a
for (int first = 0; first < n; ++first) {
// 需要和上一次枚举的数不相同
if (first > 0 && nums[first] == nums[first - 1]) {
continue;
}
// c 对应的指针初始指向数组的最右端
int third = n - 1;
int target = -nums[first];
// 枚举 b
for (int second = first + 1; second < n; ++second) {
// 需要和上一次枚举的数不相同
if (second > first + 1 && nums[second] == nums[second - 1]) {
continue;
}
// 需要保证 b 的指针在 c 的指针的左侧
while (second < third && nums[second] + nums[third] > target) {
--third;
}
// 如果指针重合,随着 b 后续的增加
// 就不会有满足 a+b+c=0 并且 b<c 的 c 了,可以退出循环
if (second == third) {
break;
}
if (nums[second] + nums[third] == target) {
ans.push_back({nums[first], nums[second], nums[third]});
}
}
}
return ans;
}
};
16. 3Sum Closest
Given an array nums of n integers and an integer target, find three integers in nums such that the sum is closest to target. Return the sum of the three integers. You may assume that each input would have exactly one solution.
- Example:
Given array nums = [-1, 2, 1, -4], and target = 1.
The sum that is closest to the target is 2. (-1 + 2 + 1 = 2).
- 思路
排序与双指针:先排序,从小遍历 a,然后在 a 的后面便利 b 和 c,遍历 b 和 c 可以借鉴盛最多水容器题目相似,指针移动顺序有所差别。
- code:
class Solution {
public:
int threeSumClosest(vector<int>& nums, int target) {
sort(nums.begin(), nums.end());
int n = nums.size();
int best = 1e7;
// 根据差值的绝对值来更新答案
auto update = [&](int cur) {
if (abs(cur - target) < abs(best - target)) {
best = cur;
}
};
// 枚举 a
for (int i = 0; i < n; ++i) {
// 保证和上一次枚举的元素不相等
if (i > 0 && nums[i] == nums[i - 1]) {
continue;
}
// 使用双指针枚举 b 和 c
int j = i + 1, k = n - 1;
while (j < k) {
int sum = nums[i] + nums[j] + nums[k];
// 如果和为 target 直接返回答案
if (sum == target) {
return target;
}
update(sum);
if (sum > target) {
// 如果和大于 target,移动 c 对应的指针
int k0 = k - 1;
// 移动到下一个不相等的元素
while (j < k0 && nums[k0] == nums[k]) {
--k0;
}
k = k0;
} else {
// 如果和小于 target,移动 b 对应的指针
int j0 = j + 1;
// 移动到下一个不相等的元素
while (j0 < k && nums[j0] == nums[j]) {
++j0;
}
j = j0;
}
}
}
return best;
}
};
17. Letter Combinations of a Phone Number
Given a string containing digits from 2-9 inclusive, return all possible letter combinations that the number could represent.
A mapping of digit to letters (just like on the telephone buttons) is given below. Note that 1 does not map to any letters.
![LeetCode2](https://i-blog.csdnimg.cn/blog_migrate/8ca10877dcff6501f6c4e4379b53791f.jpeg)
- 思路
回溯,递归
- code:
class Solution {
public:
vector<string> letterCombinations(string digits) {
vector<string> combinations;
if (digits.empty()) {
return combinations;
}
unordered_map<char, string> phoneMap{
{'2', "abc"},
{'3', "def"},
{'4', "ghi"},
{'5', "jkl"},
{'6', "mno"},
{'7', "pqrs"},
{'8', "tuv"},
{'9', "wxyz"}
};
string combination;
backtrack(combinations, phoneMap, digits, 0, combination);
return combinations;
}
void backtrack(vector<string>& combinations, const unordered_map<char, string>& phoneMap, const string& digits, int index, string& combination) {
if (index == digits.length()) {
combinations.push_back(combination);
} else {
char digit = digits[index];
const string& letters = phoneMap.at(digit);
for (const char& letter: letters) {
combination.push_back(letter);
backtrack(combinations, phoneMap, digits, index + 1, combination);
combination.pop_back();
}
}
}
};
18. 4Sum
Given an array nums of n integers and an integer target, are there elements a, b, c, and d in nums such that a + b + c + d = target? Find all unique quadruplets in the array which gives the sum of target.
- Example:
Given array nums = [1, 0, -1, 0, -2, 2], and target = 0.
A solution set is:
[
[-1, 0, 0, 1],
[-2, -1, 1, 2],
[-2, 0, 0, 2]
]
- code:
class Solution {
public:
vector<vector<int>> fourSum(vector<int>& nums, int target) {
vector<vector<int>> quadruplets;
if (nums.size() < 4) {
return quadruplets;
}
sort(nums.begin(), nums.end());
int length = nums.size();
for (int i = 0; i < length - 3; i++) {
if (i > 0 && nums[i] == nums[i - 1]) {
continue;
}
if (nums[i] + nums[i + 1] + nums[i + 2] + nums[i + 3] > target) {
break;
}
if (nums[i] + nums[length - 3] + nums[length - 2] + nums[length - 1] < target) {
continue;
}
for (int j = i + 1; j < length - 2; j++) {
if (j > i + 1 && nums[j] == nums[j - 1]) {
continue;
}
if (nums[i] + nums[j] + nums[j + 1] + nums[j + 2] > target) {
break;
}
if (nums[i] + nums[j] + nums[length - 2] + nums[length - 1] < target) {
continue;
}
int left = j + 1, right = length - 1;
while (left < right) {
int sum = nums[i] + nums[j] + nums[left] + nums[right];
if (sum == target) {
quadruplets.push_back({nums[i], nums[j], nums[left], nums[right]});
while (left < right && nums[left] == nums[left + 1]) {
left++;
}
left++;
while (left < right && nums[right] == nums[right - 1]) {
right--;
}
right--;
} else if (sum < target) {
left++;
} else {
right--;
}
}
}
}
return quadruplets;
}
};
19. Remove Nth Node From End of List
Given a linked list, remove the n-th node from the end of list and return its head.
- Example:
Given linked list: 1->2->3->4->5, and n = 2.
After removing the second node from the end, the linked list becomes 1->2->3->5.
- code:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:// 比较通用的题目
ListNode* removeNthFromEnd(ListNode* head, int n) {
ListNode* delPos = new ListNode(0);
delPos->next = head;
ListNode* curr = head;
int cn = n;
while (cn--) curr = curr->next;
while (curr != nullptr) {
curr = curr->next;
delPos = delPos->next;
}
if (delPos->next == head) {
return head->next;
}
delPos->next = delPos->next->next;
return head;
}
};
20. Valid Parentheses
Given a string containing just the characters ‘(’, ‘)’, ‘{’, ‘}’, ‘[’ and ‘]’, determine if the input string is valid.
-
An input string is valid if:
- Open brackets must be closed by the same type of brackets.
- Open brackets must be closed in the correct order.
-
Example:
Input: "()"
Output: true
Input: "()[]{}"
Output: true
Input: "([)]"
Output: false
Input: "{[]}"
Output: true
- code:
class Solution {
public:
bool isValid(string s) {
int n = s.size();
if (n % 2 == 1) {
return false;
}
unordered_map<char, char> pairs = {
{')', '('},
{']', '['},
{'}', '{'}
};
stack<char> stk;
for (char ch: s) {
if (pairs.count(ch)) {
if (stk.empty() || stk.top() != pairs[ch]) {
return false;
}
stk.pop();
}
else {
stk.push(ch);
}
}
return stk.empty();
}
};
21. Merge Two Sorted Lists
Merge two sorted linked lists and return it as a new list. The new list should be made by splicing together the nodes of the first two lists.
- Example:
Input: 1->2->4, 1->3->4
Output: 1->1->2->3->4->4
- 思路
迭代最优,递归次之
- code:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
ListNode* preHead = new ListNode(-1);
ListNode* prev = preHead;
while (l1 != nullptr && l2 != nullptr) {
if (l1->val < l2->val) {
prev->next = l1;
l1 = l1->next;
} else {
prev->next = l2;
l2 = l2->next;
}
prev = prev->next;
}
// 合并后 l1 和 l2 最多只有一个还未被合并完,我们直接将链表末尾指向未合并完的链表即可
prev->next = l1 == nullptr ? l2 : l1;
return preHead->next;
}
};
22. Generate Parentheses !!!
Given n pairs of parentheses, write a function to generate all combinations of well-formed parentheses.
- Example:
For example, given n = 3, a solution set is:
[
"((()))",
"(()())",
"(())()",
"()(())",
"()()()"
]
- code:
class Solution {
public:
vector <string> res;
void generateseries(int open, int closed, string str) {
if (open == 0 && closed == 0){
res.push_back(str);
return;
}
if (open>0) {
generateseries(open - 1, closed, str + '(');
}
if (closed>open && closed>0) {
generateseries(open, closed - 1, str + ')');
}
}
vector<string> generateParenthesis(int n) {
generateseries(n, n, "");
return res;
}
};
23. Merge k Sorted Lists
Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity.
- Example:
Input:
[
1->4->5,
1->3->4,
2->6
]
Output: 1->1->2->3->4->4->5->6
- 思路:
最优基于优先队列;次优使用合并俩列表的函数,顺序或者二分合并
- code:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
struct Status {
int val;
ListNode *ptr;
bool operator < (const Status &rhs) const {
return val > rhs.val;
}
};
priority_queue <Status> q;
ListNode* mergeKLists(vector<ListNode*>& lists) {
for (auto node: lists) {
if (node) q.push({node->val, node});
}
ListNode head, *tail = &head;
while (!q.empty()) {
auto f = q.top(); q.pop();
tail->next = f.ptr;
tail = tail->next;
if (f.ptr->next) q.push({f.ptr->next->val, f.ptr->next});
}
return head.next;
}
};
24. Swap Nodes in Pairs
Given a linked list, swap every two adjacent nodes and return its head.
- Example:
Given 1->2->3->4, you should return the list as 2->1->4->3.
- 思路
递归或者迭代
- code:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* swapPairs(ListNode* head) {
ListNode* dummyHead = new ListNode(0);
dummyHead->next = head;
ListNode* temp = dummyHead;
while (temp->next != nullptr && temp->next->next != nullptr) {
ListNode* node1 = temp->next;
ListNode* node2 = temp->next->next;
temp->next = node2;
node1->next = node2->next;
node2->next = node1;
temp = node1;
}
return dummyHead->next;
}
};
25. Reverse Nodes in k-Group
Given a linked list, reverse the nodes of a linked list k at a time and return its modified list.
k is a positive integer and is less than or equal to the length of the linked list. If the number of nodes is not a multiple of k then left-out nodes in the end should remain as it is.
- Example:
Given this linked list: 1->2->3->4->5
For k = 2, you should return: 2->1->4->3->5
For k = 3, you should return: 3->2->1->4->5
- code:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
int getListLen(ListNode* head){
if (!head)
return 0;
int len = 1;
ListNode* tmp = head;
while (tmp->next){
++len;
tmp = tmp->next;
}
return len;
}
ListNode* reverseKGroup(ListNode* head, int k) {
int len = getListLen(head);
if (len < k)
return head;
int group_number = len / k;
ListNode* newHead = new ListNode(0);
newHead->next = head;
ListNode* prev = newHead;
ListNode* curr = head;
int reverse_times = 0;
while (reverse_times < group_number){
int i = 0;
while (i != k - 1){
ListNode* post = curr->next;
curr->next = post->next;
post->next = prev->next;
prev->next = post;
++i;
}
prev = curr;
curr = prev->next;
++reverse_times;
}
return newHead->next;
}
};
26. Remove Duplicates from Sorted Array
Given a sorted array nums, remove the duplicates in-place such that each element appear only once and return the new length.
Do not allocate extra space for another array, you must do this by modifying the input array in-place with O(1) extra memory.
- Example:
Given nums = [1,1,2],
Your function should return length = 2, with the first two elements of nums being 1 and 2 respectively.
It doesn't matter what you leave beyond the returned length.
- code:
class Solution {
public:
int removeDuplicates(vector<int>& nums) {
int n = 0;
for (int i = 1; i < nums.size(); i++) {
if (nums[n] != nums[i]) {
n++;
nums[n] = nums[i];
}
}
return nums.size() ? n + 1 : n;
}
};
27. Remove Element
Given an array nums and a value val, remove all instances of that value in-place and return the new length.
Do not allocate extra space for another array, you must do this by modifying the input array in-place with O(1) extra memory.
The order of elements can be changed. It doesn’t matter what you leave beyond the new length.
- Example:
Given nums = [3,2,2,3], val = 3,
Your function should return length = 2, with the first two elements of nums being 2.
It doesn't matter what you leave beyond the returned length.
- code:
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
if (nums.size() == 0) {
return 0;
}
int idx = 0;
for (int i = 0; i < nums.size(); i++) {
if (nums[i] != val) {
nums[idx++] = nums[i];
}
}
return idx;
}
};
28. Implement strStr()
Implement strStr().
Return the index of the first occurrence of needle in haystack, or -1 if needle is not part of haystack.
- Example:
Input: haystack = "hello", needle = "ll"
Output: 2
Input: haystack = "aaaaa", needle = "bba"
Output: -1
- 思路
KMP 算法:https://www.cnblogs.com/yjiyjige/p/3263858.html 真饶人
- code:
class Solution {
public:// kmp 算法
vector<int>next;
void makenext(string s){
int n = s.length();
for(int i = 0; i < n; ++ i) next.push_back(0);
for(int i = 0, j = 1; j < n; ++ j){
while(i > 0 && s[i] != s[j]) i = next[i - 1];
if(s[i] == s[j]) i++;
next[j] = i;
}
}
int index = -1;
int strStr(string haystack, string needle) {
int m = haystack.length();
int n = needle.length();
if(n == 0) return 0;
makenext(needle);
for(int i = 0, j = 0; i < m; ++ i){
while(j > 0 && haystack[i] != needle[j]) j = next[j - 1];
if(haystack[i] == needle[j]) j++;
if(j == n){
index = i - n + 1;
break;
}
}
return index;
}
};
29. Divide Two Integers
Given two integers dividend and divisor, divide two integers without using multiplication, division and mod operator.
Return the quotient after dividing dividend by divisor.
The integer division should truncate toward zero.
- Example:
Input: dividend = 10, divisor = 3
Output: 3
Input: dividend = 7, divisor = -3
Output: -2
- code:
class Solution {
public:
int divide(int dividend, int divisor) {
if (dividend == 0) {
return 0;
}
int symbol = 1;
if ((dividend > 0 && divisor < 0) || (dividend < 0 && divisor > 0)) {
symbol = -1;
}
long dividend_l = dividend;
long divisor_l = divisor;
dividend_l = dividend_l < 0 ? -dividend_l : dividend_l;
divisor_l = divisor_l < 0 ? -divisor_l : divisor_l;
long multiple = 0;
while (dividend_l >= divisor_l) {
long divisor_cp = divisor_l;
long mul = 1;
while (dividend_l >= divisor_cp + divisor_cp) {
divisor_cp += divisor_cp;
mul += mul;
}
dividend_l -= divisor_cp;
multiple += mul;
}
if (multiple*symbol > INT_MAX) {
return INT_MAX;
}
return int(multiple*symbol);
}
};
30. Substring with Concatenation of All Words
You are given a string, s, and a list of words, words, that are all of the same length. Find all starting indices of substring(s) in s that is a concatenation of each word in words exactly once and without any intervening characters.
- Example:
Input:
s = "barfoothefoobarman",
words = ["foo","bar"]
Output: [0,9]
Explanation: Substrings starting at index 0 and 9 are "barfoor" and "foobar" respectively.
The output order does not matter, returning [9,0] is fine too.
Input:
s = "wordgoodstudentgoodword",
words = ["word","student"]
Output: []
- code:
class Solution {
public:
vector<int> findSubstring(string s, vector<string>& words) {
int n = s.length(), cnt = words.size();
vector<int> ans;
if (n <= 0 || cnt <= 0)
return ans;
unordered_map<string, int> dict;
for (int i = 0; i<cnt; i++)
dict[words[i]]++;
int wl = words[0].length();
for (int i = 0; i<wl; i++) {
unordered_map<string, int> t_dict;
int count = 0;
int lft = i;
for (int j = i; j <= n - wl; j += wl) { //一次走一个单词
string str = s.substr(j, wl);
if (dict.count(str)>0) {
t_dict[str]++;
count++;
while (t_dict[str]>dict[str]) {// 这里检验有重复的,从头开始剔除,直到没重复
t_dict[s.substr(lft, wl)]--;
count--;
lft += wl;
}
if (count == cnt) {
ans.push_back(lft);
t_dict[s.substr(lft, wl)]--;
lft += wl;
count--;
}
} else {
count = 0;
t_dict.clear();
lft = j + wl;
}
}
}
return ans;
}
};
31. Next Permutation
Implement next permutation, which rearranges numbers into the lexicographically next greater permutation of numbers.
If such arrangement is not possible, it must rearrange it as the lowest possible order (ie, sorted in ascending order).
The replacement must be in-place and use only constant extra memory.
Here are some examples. Inputs are in the left-hand column and its corresponding outputs are in the right-hand column.
- Example:
1,2,3 → 1,3,2
3,2,1 → 1,2,3
1,1,5 → 1,5,1
- 思路
从右往左,找第一个非升序元素,然后从右往左找到第一个比上元素大的元素进行替换,然后把右边的进行反转
- code:
class Solution {
public:
void nextPermutation(vector<int>& nums) {
int i = nums.size() - 2;
while (i >= 0 && nums[i] >= nums[i + 1]) {
i--;
}
if (i >= 0) {
int j = nums.size() - 1;
while (j >= 0 && nums[i] >= nums[j]) {
j--;
}
swap(nums[i], nums[j]);
}
reverse(nums.begin() + i + 1, nums.end());
}
};
32. Longest Valid Parentheses
Given a string containing just the characters ‘(’ and ‘)’, find the length of the longest valid (well-formed) parentheses substring.
- Example:
Input: "(()"
Output: 2
Explanation: The longest valid parentheses substring is "()"
Input: ")()())"
Output: 4
Explanation: The longest valid parentheses substring is "()()"
- code:
class Solution {
public:
int longestValidParentheses(string s) {
stack<int> paranStack;
int maxLength = 0;
int lastValidIndx = 0;
for (int indx = 0; indx<s.length(); indx++) {
if (s[indx] == '(') //遇到左括号,直接存入。
paranStack.push(indx);
else { //遇到右括号,分情况讨论
if (paranStack.empty()) {
//如果此时栈里左括号已经被消耗完了,没有额外的左括号用来配对当前的右括号了,那么当前的右括号就被单出来了,表明当前子串可以结束了,此时的右括号也成为了下一个group的分界点,此时右括号下标为index,所以下一个group的起始点为index+1,相当于skip掉当前的右括号。
lastValidIndx = indx + 1;
} else { //如果此时栈不空,可能有两种情况,1)栈正好剩下1个左括号和当前右括号配对 2)栈剩下不止1个左括号,
paranStack.pop();
if (paranStack.empty()) {
//栈pop()之前正好剩下1个左括号,pop()之后,栈空了,此时group长度为indx-lastValidIndx
maxLength = max(maxLength, indx - lastValidIndx + 1);
} else {
//栈有pop()之前剩下不止1个左括号,此时额外多出的左括号使得新的group形成。如()(()())中index=4时,stack中有2个左括号
maxLength = max(maxLength, indx - paranStack.top());
}
}
}
}
return maxLength;
}
};
33. Search 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]).
You are given a target value to search. If found in the array return its index, otherwise return -1.
You may assume no duplicate exists in the array.
Your algorithm’s runtime complexity must be in the order of O(log n).
- Example:
Input: nums = [4,5,6,7,0,1,2], target = 0
Output: 4
Input: nums = [4,5,6,7,0,1,2], target = 3
Output: -1
- 思路
二分法,只要知道左边或右边为是有序的就能用二分发找到 target;先用二分法找有序,再用二分法找 target。
- code:
class Solution {
public:
int search(vector<int>& nums, int target) {
int n = (int)nums.size();
if (!n) {
return -1;
}
if (n == 1) {
return nums[0] == target ? 0 : -1;
}
int l = 0, r = n - 1;
while (l <= r) {
int mid = (l + r) / 2;
if (nums[mid] == target) return mid;
if (nums[0] <= nums[mid]) {
if (nums[0] <= target && target < nums[mid]) {
r = mid - 1;
} else {
l = mid + 1;
}
} else {
if (nums[mid] < target && target <= nums[n - 1]) {
l = mid + 1;
} else {
r = mid - 1;
}
}
}
return -1;
}
};
34. Find First and Last Position of Element in Sorted Array
Given an array of integers nums sorted in ascending order, find the starting and ending position of a given target value.
Your algorithm’s runtime complexity must be in the order of O(log n).
If the target is not found in the array, return [-1, -1].
- Example:
Input: nums = [5,7,7,8,8,10], target = 8
Output: [3,4]
Input: nums = [5,7,7,8,8,10], target = 6
Output: [-1,-1]
- code:
class Solution {
public:
vector<int> searchRange(vector<int>& nums, int target) {
vector<int> result(2, -1);
int m = -1;
for (size_t b = 0, e = nums.size(); e - b > 0; ) {
m = b + (e - b)/2;
if (nums[m] == target) {
for (int m0 = m; nums[m0] == target && m0 >= 0; m0--) {
result[0] = m0;
}
for (int m0 = m; nums[m0] == target && m0 < nums.size(); m0++) {
result[1] = m0;
}
break;
}
else if (nums[m] < target) {
b = m+1;
} else {
e = m;
}
}
return result;
}
};
35. Search Insert Position
Given a sorted array and a target value, return the index if the target is found. If not, return the index where it would be if it were inserted in order.
You may assume no duplicates in the array.
- Example:
Input: [1,3,5,6], 5
Output: 2
Input: [1,3,5,6], 2
Output: 1
Input: [1,3,5,6], 7
Output: 4
- code:
class Solution {
public:
int searchInsert(vector<int>& nums, int target) {
int left = 0, right = nums.size() - 1;
while(left <= right) {
int middle = (left + right) / 2;
if(target == nums[middle]) {
return middle;
} else if(target < nums[middle]) {
right = middle - 1;
} else {
left = middle + 1;
}
}
return right + 1;
}
};
36. Valid Sudoku
Determine if a 9x9 Sudoku board is valid. Only the filled cells need to be validated according to the following rules:
- Each row must contain the digits 1-9 without repetition.
- Each column must contain the digits 1-9 without repetition.
- Each of the 9 3x3 sub-boxes of the grid must contain the digits 1-9 without repetition.
![LeetCode3](https://i-blog.csdnimg.cn/blog_migrate/9d395bc26b9a19c0ef5da63d22b552a1.jpeg)
- Example:
Input:
[
["5","3",".",".","7",".",".",".","."],
["6",".",".","1","9","5",".",".","."],
[".","9","8",".",".",".",".","6","."],
["8",".",".",".","6",".",".",".","3"],
["4",".",".","8",".","3",".",".","1"],
["7",".",".",".","2",".",".",".","6"],
[".","6",".",".",".",".","2","8","."],
[".",".",".","4","1","9",".",".","5"],
[".",".",".",".","8",".",".","7","9"]
]
Output: true
- 思路
行无重复,列无重复,3x3 无重复
- code:
class Solution:
def isValidSudoku(self, board):
"""
:type board: List[List[str]]
:rtype: bool
"""
# init data
rows = [{} for i in range(9)]
columns = [{} for i in range(9)]
boxes = [{} for i in range(9)]
# validate a board
for i in range(9):
for j in range(9):
num = board[i][j]
if num != '.':
num = int(num)
box_index = (i // 3 ) * 3 + j // 3
# keep the current cell value
rows[i][num] = rows[i].get(num, 0) + 1
columns[j][num] = columns[j].get(num, 0) + 1
boxes[box_index][num] = boxes[box_index].get(num, 0) + 1
# check if this value has been already seen before
if rows[i][num] > 1 or columns[j][num] > 1 or boxes[box_index][num] > 1:
return False
return True
37. Sudoku Solver
Write a program to solve a Sudoku puzzle by filling the empty cells.
- code:
class Solution {
private:
bool line[9][9];
bool column[9][9];
bool block[3][3][9];
bool valid;
vector<pair<int, int>> spaces;
public:
void dfs(vector<vector<char>>& board, int pos) {
if (pos == spaces.size()) {
valid = true;
return;
}
auto [i, j] = spaces[pos];
for (int digit = 0; digit < 9 && !valid; ++digit) {
if (!line[i][digit] && !column[j][digit] && !block[i / 3][j / 3][digit]) {
line[i][digit] = column[j][digit] = block[i / 3][j / 3][digit] = true;
board[i][j] = digit + '0' + 1;
dfs(board, pos + 1);
line[i][digit] = column[j][digit] = block[i / 3][j / 3][digit] = false;
}
}
}
void solveSudoku(vector<vector<char>>& board) {
memset(line, false, sizeof(line));
memset(column, false, sizeof(column));
memset(block, false, sizeof(block));
valid = false;
for (int i = 0; i < 9; ++i) {
for (int j = 0; j < 9; ++j) {
if (board[i][j] == '.') {
spaces.emplace_back(i, j);
}
else {
int digit = board[i][j] - '0' - 1;
line[i][digit] = column[j][digit] = block[i / 3][j / 3][digit] = true;
}
}
}
dfs(board, 0);
}
};
38. Count and Say
The count-and-say sequence is the sequence of integers with the first five terms as following:
1. 1
2. 11
3. 21
4. 1211
5. 111221
1 is read off as “one 1” or 11.
11 is read off as “two 1s” or 21.
21 is read off as “one 2, then one 1” or 1211.
- Example:
Input: 1
Output: "1"
Input: 4
Output: "1211"
- code:
class Solution {
public:
string CountAndSay(string &str) {
string res;
for (int i = 0; i < str.size(); i++) {
int count = 1;
while (i < str.size() - 1 && str[i] == str[i + 1]) {
count++, i++;
}
res += to_string(count) + str[i];
}
return res;
}
string countAndSay(int n) {
string res = "1";
for (int i = 2; i <= n; i++) {
res = CountAndSay(res);
}
return res;
}
};
39. Combination Sum
Given a set of candidate numbers (candidates) (without duplicates) and a target number (target), find all unique combinations in candidates where the candidate numbers sums to target.
The same repeated number may be chosen from candidates unlimited number of times.
-
note:
- All numbers (including target) will be positive integers.
- The solution set must not contain duplicate combinations.
-
Example:
Input: candidates = [2,3,6,7], target = 7,
A solution set is:
[
[7],
[2,2,3]
]
Input: candidates = [2,3,5], target = 8,
A solution set is:
[
[2,2,2,2],
[2,3,3],
[3,5]
]
- 思路
深度优先搜索
- code:
class Solution {
public:
void dfs(vector<int>& candidates, int target, vector<vector<int>>& ans, vector<int>& combine, int idx) {
if (idx == candidates.size()) {
return;
}
if (target == 0) {
ans.emplace_back(combine);
return;
}
// 直接跳过
dfs(candidates, target, ans, combine, idx + 1);
// 选择当前数
if (target - candidates[idx] >= 0) {
combine.emplace_back(candidates[idx]);
dfs(candidates, target - candidates[idx], ans, combine, idx);
combine.pop_back();
}
}
vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
vector<vector<int>> ans;
vector<int> combine;
dfs(candidates, target, ans, combine, 0);
return ans;
}
};
40. Combination Sum II
Given a collection of candidate numbers (candidates) and a target number (target), find all unique combinations in candidates where the candidate numbers sums to target.
Each number in candidates may only be used once in the combination.
-
note:
- All numbers (including target) will be positive integers.
- The solution set must not contain duplicate combinations.
-
Example:
Input: candidates = [10,1,2,7,6,1,5], target = 8,
A solution set is:
[
[1, 7],
[1, 2, 5],
[2, 6],
[1, 1, 6]
]
Input: candidates = [2,5,2,1,2], target = 5,
A solution set is:
[
[1,2,2],
[5]
]
- code:
class Solution {
private:
vector<pair<int, int>> freq;
vector<vector<int>> ans;
vector<int> sequence;
public:
void dfs(int pos, int rest) {
if (rest == 0) {
ans.push_back(sequence);
return;
}
if (pos == freq.size() || rest < freq[pos].first) {
return;
}
dfs(pos + 1, rest);
int most = min(rest / freq[pos].first, freq[pos].second);
for (int i = 1; i <= most; ++i) {
sequence.push_back(freq[pos].first);
dfs(pos + 1, rest - i * freq[pos].first);
}
for (int i = 1; i <= most; ++i) {
sequence.pop_back();
}
}
vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
sort(candidates.begin(), candidates.end());
for (int num: candidates) {
if (freq.empty() || num != freq.back().first) {
freq.emplace_back(num, 1);
} else {
++freq.back().second;
}
}
dfs(0, target);
return ans;
}
};
41. First Missing Positive!!!
Given an unsorted integer array, find the smallest missing positive integer.
- Example:
Input: [1,2,0]
Output: 3
Input: [3,4,-1,1]
Output: 2
Input: [7,8,9,11,12]
Output: 1
- 思路
返回值肯定是小于数组长度
- code:
class Solution {
public:
int firstMissingPositive(vector<int>& A) {
if(A.empty()) return 1;
int n = A.size();
for(int i = 0; i < n; ++ i)
while(A[i] > 0 && A[i] <= n && A[A[i] - 1] != A[i]) // 这里防止信息泄露
swap(A[i], A[A[i] - 1]);
for(int i = 0; i < n; ++ i)
if(A[i] != i + 1)
return i + 1;
return n + 1;
}
};
42. Trapping Rain Water
Given n non-negative integers representing an elevation map where the width of each bar is 1, compute how much water it is able to trap after raining.
![LeetCode4](https://i-blog.csdnimg.cn/blog_migrate/23fd635f6be46cfea004c3211ecb9419.jpeg)
The above elevation map is represented by array [0,1,0,2,1,0,1,3,2,1,2,1]. In this case, 6 units of rain water (blue section) are being trapped. Thanks Marcos for contributing this image!
- Example:
Input: [0,1,0,2,1,0,1,3,2,1,2,1]
Output: 6
- 思路
动态规划
- code:
class Solution {
public:
int trap(vector<int>& height) {
int n = height.size();
if (n == 0) {
return 0;
}
vector<int> leftMax(n);
leftMax[0] = height[0];
for (int i = 1; i < n; ++i) {
leftMax[i] = max(leftMax[i - 1], height[i]);
}
vector<int> rightMax(n);
rightMax[n - 1] = height[n - 1];
for (int i = n - 2; i >= 0; --i) {
rightMax[i] = max(rightMax[i + 1], height[i]);
}
int ans = 0;
for (int i = 0; i < n; ++i) {
ans += min(leftMax[i], rightMax[i]) - height[i];
}
return ans;
}
};
43. Multiply Strings
Given two non-negative integers num1 and num2 represented as strings, return the product of num1 and num2, also represented as a string.
-
note:
- The length of both num1 and num2 is < 110.
- Both num1 and num2 contain only digits 0-9.
- Both num1 and num2 do not contain any leading zero, except the number 0 itself.
- You must not use any built-in BigInteger library or convert the inputs to integer directly.
-
Example:
Input: num1 = "2", num2 = "3"
Output: "6"
Input: num1 = "123", num2 = "456"
Output: "56088"
- code:
class Solution {
public:
string multiply(string num1, string num2) {
vector<int> table(num1.size() + num2.size(), 0);
for (int i = num2.size() - 1; i >= 0; i--) {
for (int j = num1.size() - 1; j >= 0; j--)
{
int twodigits = (num2[i] - '0') * (num1[j] - '0');
table[num2.size() - 1 - i + num1.size() - 1 - j] += twodigits % 10;
table[num2.size() - 1 - i + num1.size() - 1 - j + 1] += twodigits / 10;
}
}
string ans = "";
int remainder = 0;
for (int i = 0; i < table.size(); i++) {
int digit = (remainder + table[i]) % 10;
remainder = (remainder + table[i]) / 10;
ans.push_back(digit + '0');
}
while (ans.back() == '0' && ans.size() > 1) {
ans.pop_back();
}
reverse(ans.begin(), ans.end());
return ans;
}
};
44. Wildcard Matching
Given an input string (s) and a pattern §, implement wildcard pattern matching with support for ‘?’ and ‘*’.
'?' Matches any single character.
'*' Matches any sequence of characters (including the empty sequence).
The matching should cover the entire input string (not partial).
-
note:
- s could be empty and contains only lowercase letters a-z.
- p could be empty and contains only lowercase letters a-z, and characters like ? or *.
-
Example:
Input:
s = "aa"
p = "a"
Output: false
Explanation: "a" does not match the entire string "aa".
Input:
s = "aa"
p = "*"
Output: true
Explanation: '*' matches any sequence.
Input:
s = "cb"
p = "?a"
Output: false
Explanation: '?' matches 'c', but the second letter is 'a', which does not match 'b'.
Input:
s = "adceb"
p = "*a*b"
Output: true
Explanation: The first '*' matches the empty sequence, while the second '*' matches the substring "dce".
Input:
s = "acdcb"
p = "a*c?b"
Output: false
- 思路
动态规划,或者尽量让 * 扩展,不行再回撤。
- code:
public:
bool isMatch(string s, string p) {
int i = 0, j = 0, sPos = -1, starPos = -1;
while (i < s.size()) {
if (j < p.size() && (s[i] == p[j] || p[j] == '?')) {
i++, j++;
} else if (j < p.size() && p[j] == '*') {
sPos = i, starPos = j; // 除非遇见 '*' 要不然始终保持前面出现'*'处
j++;
} else if (starPos != -1) {
j = starPos + 1;
i = ++sPos;
} else {
return false;
}
}
while (j < p.size() && p[j] == '*') j++;
return j == p.size();
}
};
45. Jump Game II
Given an array of non-negative integers, you are initially positioned at the first index of the array.
Each element in the array represents your maximum jump length at that position.
Your goal is to reach the last index in the minimum number of jumps.
- Example:
Input: [2,3,1,1,4]
Output: 2
Explanation: The minimum number of jumps to reach the last index is 2.
Jump 1 step from index 0 to 1, then 3 steps to the last index.
- code:
class Solution {
public:
int jump(vector<int>& nums) {
int i = 0;
int level = 0;
int cur = 0;
int next = 0;
//bfs的思想
while(i < nums.size()){
if(cur >= nums.size() - 1){
return level;
}
level++;
for(; i <= cur; i++){
next = max(next, nums[i] + i);
}
cur = next;
}
return level;
}
};
46. Permutations
Given a collection of distinct integers, return all possible permutations.
- Example:
Input: [1,2,3]
Output:
[
[1,2,3],
[1,3,2],
[2,1,3],
[2,3,1],
[3,1,2],
[3,2,1]
]
- 思路
深度优先搜索
- code:
class Solution {
public:
void backtrack(vector<vector<int>>& res, vector<int>& output, int first, int len){
// 所有数都填完了
if (first == len) {
res.emplace_back(output);
return;
}
for (int i = first; i < len; ++i) {
// 动态维护数组
swap(output[i], output[first]);
// 继续递归填下一个数
backtrack(res, output, first + 1, len);
// 撤销操作
swap(output[i], output[first]);
}
}
vector<vector<int>> permute(vector<int>& nums) {
vector<vector<int> > res;
backtrack(res, nums, 0, (int)nums.size());
return res;
}
};
47. Permutations II!!!
Given a collection of numbers that might contain duplicates, return all possible unique permutations.
- Example:
Input: [1,1,2]
Output:
[
[1,1,2],
[1,2,1],
[2,1,1]
]
- code:
class Solution {
vector<int> vis;
public:
void backtrack(vector<int>& nums, vector<vector<int>>& ans, int idx, vector<int>& perm) {
if (idx == nums.size()) {
ans.emplace_back(perm);
return;
}
for (int i = 0; i < (int)nums.size(); ++i) {
// 每次填入的数一定是这个数所在重复数集合中从左往右第一个未被填过的数字
if (vis[i] || (i > 0 && nums[i] == nums[i - 1] && !vis[i - 1])) {
continue;
}
perm.emplace_back(nums[i]);
vis[i] = 1;
backtrack(nums, ans, idx + 1, perm);
vis[i] = 0;
perm.pop_back();
}
}
vector<vector<int>> permuteUnique(vector<int>& nums) {
vector<vector<int>> ans;
vector<int> perm;
vis.resize(nums.size());
sort(nums.begin(), nums.end());
backtrack(nums, ans, 0, perm);
return ans;
}
};
48. Rotate Image
You are given an n x n 2D matrix representing an image.
Rotate the image by 90 degrees (clockwise).
-
note:
You have to rotate the image in-place, which means you have to modify the input 2D matrix directly. DO NOT allocate another 2D matrix and do the rotation. -
Example:
Given input matrix =
[
[ 5, 1, 9,11],
[ 2, 4, 8,10],
[13, 3, 6, 7],
[15,14,12,16]
],
rotate the input matrix in-place such that it becomes:
[
[15,13, 2, 5],
[14, 3, 4, 1],
[12, 6, 8, 9],
[16, 7,10,11]
]
- code:
class Solution {
public://可以斜着翻一次,在左右翻一次
void rotate(vector<vector<int>>& matrix) {
const int n = matrix.size();
for (int i = 0; i < n / 2; ++i) {
for (int j = i; j < n - i - 1; ++j) {
int temp = matrix[i][j];
matrix[i][j] = matrix[n - 1 - j][i];
matrix[n - 1 - j][i] = matrix[n - 1 - i][n - 1 - j];
matrix[n - 1 - i][n - 1 - j] = matrix[j][n - 1 - i];
matrix[j][n - 1 - i] = temp;
}
}
}
};
49. Group Anagrams
Given an array of strings, group anagrams together.
- Example:
Input: ["eat", "tea", "tan", "ate", "nat", "bat"],
Output:
[
["ate","eat","tea"],
["nat","tan"],
["bat"]
]
- code:
class Solution {
public:
vector<vector<string>> groupAnagrams(vector<string>& strs) {
// 自定义对 array<int, 26> 类型的哈希函数
auto arrayHash = [fn = hash<int>{}] (const array<int, 26>& arr) -> size_t {
return accumulate(arr.begin(), arr.end(), 0u, [&](size_t acc, int num) {
return (acc << 1) ^ fn(num);
});
};
unordered_map<array<int, 26>, vector<string>, decltype(arrayHash)> mp(0, arrayHash);
for (string& str: strs) {
array<int, 26> counts{};
int length = str.length();
for (int i = 0; i < length; ++i) {
counts[str[i] - 'a'] ++;
}
mp[counts].emplace_back(str);
}
vector<vector<string>> ans;
for (auto it = mp.begin(); it != mp.end(); ++it) {
ans.emplace_back(it->second);
}
return ans;
}
};
50. Pow(x, n)
Implement pow(x, n), which calculates x raised to the power n ( x n x^n xn).
- Example:
Input: 2.00000, 10
Output: 1024.00000
Input: 2.10000, 3
Output: 9.26100
Input: 2.00000, -2
Output: 0.25000
Explanation: 2-2 = 1/22 = 1/4 = 0.25
- code:
class Solution {
public:
double myPow(double x, int n) { // 个数的魅力,一次乘一个,只要牵扯到多个数的运算
double ans = 1; // 就从逻辑结构上出发,看看能不能一次运算多点
unsigned long long p; // 分解成按位的数组
if (n < 0) {
p = -n;
x = 1 / x;
} else {
p = n;
}
while (p) {
if (p & 1)
ans *= x;
x *= x;
p >>= 1;
}
return ans;
}
};