463. Island Perimeter
https://leetcode.com/problems/island-perimeter/
就是逐一遍历所有的cell,用分离的cell总的的边数减去重叠的边的数目即可。在查找重叠的边的数目的时候有一点小技巧,就是沿着其中两个方向就好,这种题目都有类似的规律,就是可以沿着上三角或者下三角形的方向来做。一刷一次ac,但是还没开始注意codestyle的问题,需要再刷一遍。
class Solution {
public:
int islandPerimeter(vector<vector<int>>& grid) {
int res = , overlap = ;
for (int i = ; i < grid.size(); i ++)
{
for (int j = ; j < grid[i].size(); j ++)
{
if (grid[i][j] == )
{
res ++;
if (j + < grid[i].size() && grid[i][j + ] == )
overlap ++;
if (i + < grid.size() && grid[i + ][j] == )
overlap ++;
}
}
} return res * - * overlap; }
};
455. Assign Cookies
https://leetcode.com/problems/assign-cookies/
给出两个序列,一个序列中的元素代表cookie的size,另外一个序列代表能满足孩子要求的最小cookie的size,问如何分配使得到的满意的孩子最多。先将两个序列都按从小到大顺序排序,然后按双路指针的方式解决。一刷一次ac,但是对于C++默认的sort函数的排序方式(从小到大还是从大大小)并不是很清楚。
算法库中的sort(beg, end, comp)函数实际使用快排,其中的comp是函数或者函数指针,签名是 bool comp(elem_type first_arg, elem_type second_arg),返回的bool值的含义是第一个参数是否应该排在第二个参数的前面。而且默认参数会将较小的参数排在前面,即sort函数默认是从小到大排序!
class Solution {
public:
int findContentChildren(vector<int>& g, vector<int>& s) {
sort(g.begin(), g.end());
sort(s.begin(), s.end());
int res = ;
for (auto i = , j = ; i < g.size() && j < s.size(); j ++)
{
if(g[i] <= s[j])
{
res ++;
i ++;
}
}
return res; }
};
453: Minimum Moves to Equal Array Elements
https://leetcode.com/problems/minimum-moves-to-equal-array-elements/
一开始自己对题目的理解出错了,浪费了不少时间。每次移动要求同时将n-1个元素加1,我看成了每次移动将其中2个元素加1。搞清楚题目真正含义之后,不太会做,参考了一下其他人的解题思路:给数组中的n-1个元素加1的操作等价于数组中“不加1的那个元素“减去1,然后数组中的所有元素都加1。我们知道,给所有的元素都加1并不能改变原数组中的数之间的差值。所以这题就转化为求最少的减1操作。而要使数组中的元素全部相等,又要使用减法。那么最少的次数就是让这些元素全部都等于数组中最小的数。所以得到的结果就是sum(所有元素和)-n*数组中最小元素。
注意看题目!一刷由于c++的api用的不熟,调用了min这个api,发现c++是没有这个api的,还有很多codestyle的问题,二刷注意了一下codestyle,一次ac,代码如下:
class Solution {
public:
int minMoves(vector<int>& nums) {
if (nums.size() == ) {
return ;
} int min_num = nums[];
int sum = ;
for (int i = ; i < nums.size(); i++) {
sum += nums[i];
if (nums[i] < min_num) {
min_num = nums[i];
}
}
return sum - min_num * nums.size();
}
};
python版的代码一行完事:
class Solution(object):
def minMoves(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
return sum(nums) - min(nums) * len(nums)
383. Ransom Note
https://leetcode.com/problems/ransom-note/
就是用后一个串合成前一个串,条件是后一个串的每个字符只能用一次,这种题都可以利用c++的字符和int型转换来构建一个长为26度数组,每个数组表示一个key(前提是全大写或者全小写)。
一刷for循环中的计数器i没有声明类型(int),编译错误。二刷一次ac。
class Solution {
public:
bool canConstruct(string ransomNote, string magazine) {
vector<int> v1();
vector<int> v2();
for (int i = ; i < ransomNote.size(); i++) {
v1[ransomNote[i] - 'a'] ++;
}
for (int i = ; i < magazine.size(); i++) {
v2[magazine[i] - 'a'] ++;
}
for (int i = ; i < ; i ++) {
if (v1[i] > v2[i]) {
return false;
}
}
return true;
}
};
404. Sum of Left Leaves
https://leetcode.com/problems/sum-of-left-leaves/
看到这种题知道用递归,但是自己的思路很长时间没有理清。递归算法只要想明白一个节点的情况,其他节点都一样。对于每个节点如果指针为空,返回0;如果该节点飞空且左子树为叶子节点,则返回左叶子节点和右子树递归结果的和,否则返回左右子树的递归结果的和.一刷在处理左子树为叶子节点的情况时少写了val,二刷一次ac。
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
int sumOfLeftLeaves(TreeNode* root) {
if (! root) {
return ;
} else if (root -> left && ! root -> left -> left && ! root -> left -> right) {
return root -> left -> val + sumOfLeftLeaves(root -> right);
} else {
return sumOfLeftLeaves(root -> left) + sumOfLeftLeaves(root -> right);
} }
};
还有一种写了两个函数的算法,其实差不多。还有一种写了两个函数的算法,其实差不多。一刷第一次调用dfs函数参数给错了,只有一个root节点不算左叶子结点。二刷出现不明bug……没解决!
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
int sumOfLeftLeaves(TreeNode* root) {
if (! root) {
return ;
} else {
return dfs(root, );
} } int dfs(TreeNode* root, bool isLeft) {
if (! root) {
return ;
} else if (isLeft && ! root -> left && ! root -> right) {
return root -> val;
} else {
return dfs(root -> left, ) + dfs(root -> right, );
}
}
};
递归算法虽然简单明了,缺点是低效。尝试非递归算法,但是效率并没有提升,可能是因为递归与非递归算法用的是相同的原理:栈。一刷没有处理root为空的情况,忘记写返回语句。二刷也没有处理root为空的情况,另外没有声明类型,并且把变量名混淆。三刷处理了root为空的情况,但是处理栈顶元素的时候直接处理栈顶元素,其实应该处理栈顶元素的左右结点。四刷一次ac。
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
int sumOfLeftLeaves(TreeNode* root) {
if (! root) {
return ;
}
int res = ;
stack<TreeNode*> s;
s.push(root); while (!s.empty()) {
TreeNode* node = s.top();
s.pop(); if (node -> left) {
if (! node -> left -> left && ! node -> left -> right) {
res += node -> left -> val;
} else {
s.push(node -> left);
}
}
if (node -> right) {
s.push(node -> right);
}
}
return res;
}
};
409. Longest Palindrome
https://leetcode.com/problems/longest-palindrome/
比较简单,如果字母个数为偶数,直接加,字母个数为奇数,加上减一后的值,由于回文串中间可以放一个长度为一的子串,因此如果有个数为奇数的字母,最后结果要加一。
一刷统计小写字母的出现次数时,条件写反了。计算最后结果时注意处理出现次数为奇数的字符。二刷一次ac。
class Solution {
public:
int longestPalindrome(string s) {
vector<int> vec();
for (int i = ; i < s.size(); i++) {
if (s[i] <= 'Z' && s[i] >= 'A') {
vec[s[i] - 'A'] ++;
} else if (s[i] >= 'a' && s[i] <= 'z') {
vec[s[i] - 'a' + ] ++;
}
} bool has_odd = false;
int res = ;
for (int i = ; i < ; i++) {
if (vec[i] % == ) {
res += vec[i];
} else {
res += (vec[i] - );
has_odd = true;
}
}
if (has_odd) {
res ++;
}
return res;
}
};
448. Find All Numbers Disappeared in an Array
https://leetcode.com/problems/find-all-numbers-disappeared-in-an-array/
要求不能使用额外空间,只能在原数组上进行改动,将提到的元素对应的索引上的值加上负号,对后续的遍历操作影响不大(取绝对值就行)。由于在遍历到i之前已经将i后到元素置为负值,因此要在遍历到时候就加上绝对值。一刷中括号写成了小括号(取数组元素写成了函数调用,这两者的区别大了),在加入结果的时候少写了if语句。二刷一次ac。
class Solution {
public:
vector<int> findDisappearedNumbers(vector<int>& nums) {
vector<int> res;
for (auto n : nums) {
nums[abs(n) - ] = - abs(nums[abs(n) - ]);
}
for (int i = ; i < nums.size(); i ++) {
if (nums[i] > ) {
res.push_back(i + );
}
}
return res;
}
};
442. Find All Duplicates in an Array
https://leetcode.com/problems/find-all-duplicates-in-an-array/
题目和上面那道题差不多,而且更简单!可是我没想到。和上一题的区别在于在处理重复赋值时直接就加入结果队列了。一刷一次ac。
class Solution {
public:
vector<int> findDuplicates(vector<int>& nums) {
vector<int> res;
for (auto n : nums) {
if (nums[abs(n) - ] < ) {
res.push_back(abs(n));
} else {
nums[abs(n) - ] = - abs(nums[abs(n) - ]);
}
}
return res;
}
};
414. Third Maximum Number
https://leetcode.com/problems/third-maximum-number/
找出n个数中的第m(m < n)大的数,这是个经典问题,我去望京面试的时候就被问到,我当时真菜,不然暑假可以拿好多钱,哼!当m不太大(m<4)时,都可以按同一种思路解决 ,就是同时设置多个max,遍历数组元素,分条件更新max。注意两点,一是max的初始化一定要比当前数组元素类型的最小值要小;二是max更新条件要写全,“=”的情况要排除。
一刷各max的更新顺序写反了,max更新条件没写全,没有用更大范围的数据类型。二刷一次ac。
class Solution {
public:
int thirdMax(vector<int>& nums) {
if (! nums.size()) {
return ;
} else if (nums.size() == ) {
return nums[];
} else if (nums.size() == ) {
return nums[] > nums[] ? nums[] : nums[];
} else {
long max = LONG_MIN, sec_max = LONG_MIN, thrd_max = LONG_MIN;
for (auto n : nums) {
if (n > max) {
thrd_max = sec_max;
sec_max = max;
max = n;
} else if (n > sec_max && n < max) {
thrd_max = sec_max;
sec_max = n;
} else if (n > thrd_max && n < sec_max) {
thrd_max = n;
}
}
if (thrd_max != LONG_MIN) {
return thrd_max;
} else {
return max;
}
}
}
};
289. Game of Life
https://leetcode.com/problems/game-of-life/
一刷判断自身的条件写错,死而复生的判断条件写错,代码效率不高。二刷代码结构有优化,但是效率还是不高,判断语句中==写成赋值号=,cell周环遍历数列写错(1写成-1)。三刷没有ac是因为不理解c++_11新特性。(auto n : vec)中的n是临时变量,修改n不能改变原来vector中的元素,因此在不需要修改vector中元素时遍历可以用auto,但是要修改vector中的元素,还是需要迭代器或者下标。
class Solution {
public:
void gameOfLife(vector<vector<int>>& board) {
vector<int> ms = {-, -, -, , , , , };
vector<int> ns = {-, , , -, , -, , };
for (int i = ; i < board.size(); i++) {
for (int j = ; j < board[].size(); j++) {
int live = ;
for (int k = ; k < ; k++) {
if (i + ms[k] < board.size() && i + ms[k] >= && j + ns[k] < board[].size() && j + ns[k] >= ) {
live += (board[i + ms[k]][j + ns[k]] & );
}
}
if (board[i][j] && (live == || live == )) {
board[i][j] = ;
} else if (! board[i][j] && live == ) {
board[i][j] = ;
}
}
}
for (int i = ; i < board.size(); i++) {
for (int j = ; j < board[].size(); j++) {
board[i][j] >>= ;
}
}
}
};
287. Find the Duplicate Number
https://leetcode.com/problems/find-the-duplicate-number/
一刷使用二分法,但是对二分法中low和high的更新细节不清楚,多个同类型的变量一起声明时应该用逗号隔离。二分法中low与high的更新过程和后面的返回值是low还是mid又有什么关系,还需要一点时间来理解。看了大神的博客知道发现更高效的算法,就是转化为链表内部环检测的问题。链表成环检测的问题是一个经典问题,大神的博客分析非常精彩,核心思想是用快慢指针走过的路程和环长等进行推理和证明,最后一个恒等式的利用非常精彩。大神博客地址为:http://www.cnblogs.com/ccdev/archive/2012/09/06/2673618.html,二刷使用该方法一次ac。
class Solution {
public:
int findDuplicate(vector<int>& nums) {
int low = , high = nums.size() - ;
while (low < high) {
int mid = low + (high - low) / ;
if (count(nums, mid) > mid) {
high = mid;
} else {
low = mid + ;
}
}
return low;
} int count (vector<int>& nums, int mid) {
int c = ;
for (auto n : nums) {
if (n <= mid) {
c++;
}
}
return c;
}
};
binary search
class Solution {
public:
int findDuplicate(vector<int>& nums) {
if (nums.size() < ) {
return -;
} else {
int slow = , fast = ;
while () {
slow = nums[slow];
fast = nums[nums[fast]];
if (slow == fast) {
break;
}
}
int finder = ;
while () {
slow = nums[slow];
finder = nums[finder];
if (slow == finder) {
return slow;
}
}
}
}
};
link circle
2. Add Two Numbers
https://leetcode.com/problems/add-two-numbers/description/
将逆向链表表示的两个数加和结果也用逆向链表表示。
/**
* 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) {
int c = ;
ListNode* sum = new ListNode(), *tmp = sum;
while (l1 || l2) {
int s = c;
if (l1) {
s += l1->val;
l1 = l1->next;
}
if (l2) {
s += l2->val;
l2 = l2->next;
}
ListNode* cur = new ListNode(s % );
c = s / ;
tmp->next = cur;
tmp = cur;
}
if (c) {
ListNode* cur = new ListNode(c);
tmp->next = cur;
}
return sum->next;
}
};
24. Swap Nodes in Pairs
https://leetcode.com/problems/swap-nodes-in-pairs/description/
一次走两步。注意原链表只有一个元素时新链表为空,要对这种情况进行判别。
/**
* 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* new_head = new ListNode(), *tmp = new_head;
while (head && head->next) {
ListNode* next = head->next->next;
tmp->next = head->next;
tmp = tmp->next;
tmp->next = head;
tmp = tmp->next;
tmp->next = next;
head = next;
}
return new_head->next ? new_head->next : head;
}
};
268. Missing Number
https://leetcode.com/problems/missing-number/
一开始掉进了前面的解法的坑里,老想着把元素当作索引,将正值变负值,然后找改变后的数组中的正值对应的元素,由于同时有n和0,这两种情况不能有效区分,而且也没说可以改动数组,故抛弃了这种解法。求和再做减法更方便,由于担心溢出,用了范围更大的数据结构,好像没什么用。
class Solution {
public:
int missingNumber(vector<int>& nums) {
long long sum = ;
for (auto n : nums) {
sum += n;
}
int n = nums.size();
return n * (n + ) / - sum;
}
};
229. Majority Element II
https://leetcode.com/problems/majority-element-ii/
看了一篇博客,恍然大悟,很开心,就喜欢这种感觉。原博地址:http://blog.neoshell.moe/leetcode229.html
简而言之就是BM多数投票算法(Boyer-Moore Majority Vote algorithm)。代码效率好像不高,还要找找更高效的算法。一刷很快ac,二刷一次ac。
要注意变量的初始化,将n1,n2初始化为任意两个不同的数就行,对应counter设置为0是关键。还要注意一点第一次遍历结束只是明确了n1,n2是出现频率最高的数,但是对应的counter是不准的,需要重新计数!最后需要查看counter是否满足条件。
class Solution {
public:
vector<int> majorityElement(vector<int>& nums) {
vector<int> res();
int n1 = , n2 = , n1_counter = , n2_counter = ;
for (auto n : nums) {
if (n == n1) {
n1_counter++;
} else if (n == n2) {
n2_counter++;
} else {
if (n1_counter == ) {
n1 = n;
n1_counter++;
} else if (n2_counter == ) {
n2 = n;
n2_counter++;
} else {
n1_counter--;
n2_counter--;
}
}
}
n1_counter = ;
n2_counter = ;
for (auto n : nums) {
if (n == n1) {
n1_counter++;
} else if (n == n2) {
n2_counter++;
}
}
if (n1_counter > nums.size() / ) {
res.push_back(n1);
}
if (n2_counter > nums.size() / ) {
res.push_back(n2);
}
return res;
}
};
228. Summary Ranges
https://leetcode.com/problems/summary-ranges/
题目不难,需要注意变量的初始化和主循环之后的操作。记得返回处理结果!一刷算法效率不高,但是这是自己的思路,虽然代码写完之后自己也无法复现完整的思维过程。一开始思路不清晰,先写了一些不成熟的代码,然后不断修补,最后即使ac,思路已经支离破碎!还是需要完整而简洁的思路,如果自己没有这种思路,就去找优美的思路,然后逐行理解,把大神的思路变成自己的!
二刷我找到了一篇大神的博客,代码简洁而且思路清晰。用b记录本次范围的起始位置,用i作为索引。注意更新i和b时先更新i再更新b,而且是拿第i个元素和第i+1个元素比较,这样就不必在循环体外单独处理最后一个元素了!这点经验非常宝贵!三刷一次ac。
class Solution {
public:
vector<string> summaryRanges(vector<int>& nums) {
vector<string> res();
if (! nums.size()) {
return res;
}
int beg = , i = ;
while(i < nums.size()) {
i = beg + ;
while(nums[i] == nums[i - ] + && i < nums.size()) {
i++;
}
if (beg != i - ) {
res.push_back(to_string(nums[beg]) + "->" + to_string(nums[i - ]));
} else {
res.push_back(to_string(nums[beg]));
}
beg = i;
}
if (beg != i) {
if (beg == i - ) {
res.push_back(to_string(nums[beg]));
} else {
res.push_back(to_string(nums[beg]) + "->" + to_string(nums.size()- ));
} }
return res;
}
};
class Solution {
public:
vector<string> summaryRanges(vector<int>& nums) {
vector<string> res;
if (nums.size() < ) {
return res;
} else {
int i = , b = ;
while (i < nums.size()) {
if (i + < nums.size() && nums[i + ] == nums[i] + ) {
i ++;
} else {
if (i == b) {
res.push_back(to_string(nums[b]));
} else {
res.push_back(to_string(nums[b]) + "->" + to_string(nums[i]));
}
i ++;
b = i;
}
}
return res;
} }
};
216. Combination Sum III
https://leetcode.com/problems/combination-sum-iii/
一刷使用dfs解决。我总是不太会构造递归,要注意这种题型!用递归解决问题,只要关注解决本层次的问题就好,通过条件筛选和循环将本层解决完,调用本身进入下一层。这种说法很简单,其实不容易做到!
注意剪枝条件,比如left可能等于i,每步循环中,需先将元素插入列表尾部,在下一层递归结束后,要将插入的元素从尾部取出!
class Solution {
private:
vector<int> v;
vector<vector<int>> res; public:
vector<vector<int>> combinationSum3(int k, int n) {
dfs(k, n, );
return res;
} void dfs(int num, int left, int cur) {
if (num == && left == ) {
res.push_back(v);
}
for (int i = ; i <= ; i++) {
if (i <= left && i > cur && left >= num && left <= num * ) {
v.push_back(i);
dfs(num - , left - i, i);
v.pop_back();
}
}
}
};
recursion
547. Friend Circles
https://leetcode.com/problems/friend-circles/description/
There are N students in a class. Some of them are friends, while some are not. Their friendship is transitive in nature. For example, if A is a direct friend of B, and B is a direct friend of C, then A is an indirect friend of C. And we defined a friend circle is a group of students who are direct or indirect friends. Given a N*N matrix M representing the friend relationship between students in the class. If M[i][j] = , then the ith and jth students are direct friends with each other, otherwise not. And you have to output the total number of friend circles among all the students. Example :
Input:
[[,,],
[,,],
[,,]]
Output:
Explanation:The 0th and 1st students are direct friends, so they are in a friend circle.
The 2nd student himself is in a friend circle. So return .
Example :
Input:
[[,,],
[,,],
[,,]]
Output:
Explanation:The 0th and 1st students are direct friends, the 1st and 2nd students are direct friends,
so the 0th and 2nd students are indirect friends. All of them are in the same friend circle, so return .
Note:
N is in range [,].
M[i][i] = for all students.
If M[i][j] = , then M[j][i] = .
一刷使用DFS,还可以使用并查集解决。
class Solution {
private:
void dfs(vector<vector<int>>& M, vector<int>& m, int start, int id) {
int n = M.size();
for (int i = ; i < n + ; i++) {
if (M[start - ][i - ]) {
if (!m[i]) {
m[i] = id;
dfs(M, m, i, id);
}
}
}
}
public:
int findCircleNum(vector<vector<int>>& M) {
int n = M.size();
if (n < ) return ;
vector<int> m(n + , );
for (int i = ; i < n + ; i++) dfs(M, m, i, i);
set<int> s;
for (int i = ; i < n + ; i++) s.insert(m[i]);
return s.size();
}
};
my_dfs
class Solution {
public:
int findCircleNum(vector<vector<int>>& M) {
if (M.empty()) return ;
int n = M.size(); vector<int> leads(n, );
for (int i = ; i < n; i++) { leads[i] = i; } // initialize leads for every kid as themselves int groups = n;
for (int i = ; i < n; i++) {
for (int j = i + ; j < n; j++) { // avoid recalculate M[i][j], M[j][i]
if (M[i][j]) {
int lead1 = find(i, leads);
int lead2 = find(j, leads);
if (lead1 != lead2) { // if 2 group belongs 2 different leads, merge 2 group to 1
leads[lead1] = lead2;
groups--;
}
}
}
}
return groups;
} private:
int find(int x, vector<int>& parents) {
return parents[x] == x ? x : find(parents[x], parents);
}
};
union_find
721. Accounts Merge
https://leetcode.com/problems/accounts-merge/description/
Given a list accounts, each element accounts[i] is a list of strings, where the first element accounts[i][] is a name, and the rest of the elements are emails representing emails of the account. Now, we would like to merge these accounts. Two accounts definitely belong to the same person if there is some email that is common to both accounts. Note that even if two accounts have the same name, they may belong to different people as people could have the same name. A person can have any number of accounts initially, but all of their accounts definitely have the same name. After merging the accounts, return the accounts in the following format: the first element of each account is the name, and the rest of the elements are emails in sorted order. The accounts themselves can be returned in any order. Example :
Input:
accounts = [["John", "johnsmith@mail.com", "john00@mail.com"], ["John", "johnnybravo@mail.com"], ["John", "johnsmith@mail.com", "john_newyork@mail.com"], ["Mary", "mary@mail.com"]]
Output: [["John", 'john00@mail.com', 'john_newyork@mail.com', 'johnsmith@mail.com'], ["John", "johnnybravo@mail.com"], ["Mary", "mary@mail.com"]]
Explanation:
The first and third John's are the same person as they have the common email "johnsmith@mail.com".
The second John and Mary are different people as none of their email addresses are used by other accounts.
We could return these lists in any order, for example the answer [['Mary', 'mary@mail.com'], ['John', 'johnnybravo@mail.com'],
['John', 'john00@mail.com', 'john_newyork@mail.com', 'johnsmith@mail.com']] would still be accepted.
Note: The length of accounts will be in the range [, ].
The length of accounts[i] will be in the range [, ].
The length of accounts[i][j] will be in the range [, ].
一刷使用DFS,C++版debug很久,用python写debug方便很多,但是超时了。二刷使用并查集。上面那道题是并查集的简单题,这道属于并查集比较难的题。
class Solution(object):
def accountsMerge(self, accounts):
"""
:type accounts: List[List[str]]
:rtype: List[List[str]]
"""
accounts = sorted(accounts, key=lambda account: account[0])
visited = [-1 for _ in range(len(accounts))]
for i in range(len(accounts)):
self.dfs(accounts, visited, i, i)
for i in range(len(accounts)):
s = set(accounts[i][1:]) | set(accounts[visited[i]][1:])
l = [accounts[i][0]]
for str in list(s):
l.append(str)
accounts[visited[i]] = l
if i != visited[i]: accounts[i] = [accounts[i][0]]
res = []
for i in range(len(accounts)):
if len(accounts[i]) > 1:
res.append(sorted(accounts[i]))
return res def dfs(self, accounts, visited, start, id):
if visited[start] >= 0: return
visited[start] = id
for i in range(0, len(accounts)):
if accounts[start][0] != accounts[i][0] or i == start: continue
s = set(accounts[start][1:]) & set(accounts[i][1:])
if len(s) > 0:
self.dfs(accounts, visited, i, id)
dfs_tle
class Solution {
public:
vector<vector<string>> accountsMerge(vector<vector<string>>& accounts) {
if (accounts.empty()) return accounts;
map<string, string> parents, owner;
for (int i = ; i < accounts.size(); i++) {
for (int j = ; j < accounts[i].size(); j++) {
parents[accounts[i][j]] = accounts[i][j];
owner[accounts[i][j]] = accounts[i][];
}
}
for (int i = ; i < accounts.size(); i++) {
string p = find(accounts[i][], parents);
for (int j = ; j < accounts[i].size(); j++) parents[find(accounts[i][j], parents)] = p;
}
map<string, set<string>> unions;
for (int i = ; i < accounts.size(); i++) {
for (int j = ; j < accounts[i].size(); j++) unions[find(accounts[i][j], parents)].insert(accounts[i][j]);
}
vector<vector<string>> res;
for (auto p : unions) {
vector<string> emails(p.second.begin(), p.second.end());
sort(emails.begin(), emails.end());
emails.insert(emails.begin(), owner[p.first]);
res.push_back(emails);
}
return res;
} string find(string x, map<string, string>& parents) {
return x == parents[x] ? x : find(parents[x], parents);
}
};
union_find
720. Longest Word in Dictionary
https://leetcode.com/problems/longest-word-in-dictionary/description/
Given a list of strings words representing an English Dictionary, find the longest word in words that can be built one character at a time by other words in words. If there is more than one possible answer, return the longest word with the smallest lexicographical order. If there is no answer, return the empty string.
Example :
Input:
words = ["w","wo","wor","worl", "world"]
Output: "world"
Explanation:
The word "world" can be built one character at a time by "w", "wo", "wor", and "worl".
Example :
Input:
words = ["a", "banana", "app", "appl", "ap", "apply", "apple"]
Output: "apple"
Explanation:
Both "apply" and "apple" can be built from other words in the dictionary. However, "apple" is lexicographically smaller than "apply".
Note: All the strings in the input will only contain lowercase letters.
The length of words will be in the range [, ].
The length of words[i] will be in the range [, ].
Trie和DFS结合,一次AC。
class Solution {
public:
class Node{
public:
bool end;
vector<Node*> next;
Node() {
end = false;
next.resize(, NULL);
}
};
Node* root = new Node();
string longestWord(vector<string>& words) {
root->end = true;
for (string word: words) {
Node* tmp = root;
for (char c : word) {
if (!tmp->next[c - 'a']) tmp->next[c - 'a'] = new Node;
tmp = tmp->next[c - 'a'];
}
tmp->end = true;
}
string res = "", path = "";
dfs(root, res, path);
return res;
}
void dfs(Node* cur, string& res, string& path) {
if (!cur || !cur->end) return;
if (path.size() > res.size()) res = path;
for (int i = ; i < ; i++) {
path.push_back('a' + i);
dfs(cur->next[i], res, path);
path.pop_back();
}
}
};
677. Map Sum Pairs
https://leetcode.com/problems/map-sum-pairs/description/
Implement a MapSum class with insert, and sum methods. For the method insert, you'll be given a pair of (string, integer). The string represents the key and the integer represents the value. If the key already existed, then the original key-value pair will be overridden to the new one. For the method sum, you'll be given a string representing the prefix, and you need to return the sum of all the pairs' value whose key starts with the prefix. Example :
Input: insert("apple", ), Output: Null
Input: sum("ap"), Output:
Input: insert("app", ), Output: Null
Input: sum("ap"), Output:
Trie和BFS结合,一次AC。
class MapSum {
public:
class Node{
public:
int val;
vector<Node*> next;
Node() {
val = -;
next.resize(, NULL);
}
};
/** Initialize your data structure here. */
Node* root;
MapSum() {
root = new Node();
} void insert(string key, int val) {
Node* tmp = root;
for (char c : key) {
if (!tmp->next[c - 'a']) tmp->next[c - 'a'] = new Node();
tmp = tmp->next[c - 'a'];
}
tmp->val = val;
} int sum(string prefix) {
Node* tmp = root;
for (char c : prefix) {
if (!tmp->next[c - 'a']) return ;
tmp = tmp->next[c - 'a'];
}
int sum = ;
queue<Node*> q, next;
q.push(tmp);
while (!q.empty()) {
while (!q.empty()) {
auto cur = q.front();
q.pop();
sum += (cur && cur->val >= ? cur->val : );
if (cur) {
for (auto p : cur->next) {
if (p) next.push(p);
}
}
}
swap(q, next);
}
return sum;
}
}; /**
* Your MapSum object will be instantiated and called as such:
* MapSum obj = new MapSum();
* obj.insert(key,val);
* int param_2 = obj.sum(prefix);
*/
743. Network Delay Time
https://leetcode.com/problems/network-delay-time/description/
There are N network nodes, labelled to N. Given times, a list of travel times as directed edges times[i] = (u, v, w), where u is the source node, v is the target node, and w is the time it takes for a signal to travel from source to target. Now, we send a signal from a certain node K. How long will it take for all nodes to receive the signal? If it is impossible, return -. Note:
N will be in the range [, ].
K will be in the range [, N].
The length of times will be in the range [, ].
All edges times[i] = (u, v, w) will have <= u, v <= N and <= w <= .
一刷使用DFS没AC,debug很久,没理解错哪了。二刷使用BFS就AC。三刷使用Dijkstra算法,效率不如BFS,按理说不应该这样,还可以可以继续改进,因为BFS是Dijkstra的降级。
原来leetcode后端是用python写的!以后用pycharm写python或者intelij idea写java来debug也不错!
class Solution {
public:
vector<int> visited;
vector<vector<int>> m;
int networkDelayTime(vector<vector<int>>& times, int N, int K) {
if (N < ) return ;
m.resize(N, vector<int>(N, -));
visited.resize(N, -);
for (auto v : times) m[v[] - ][v[] - ] = v[];
dfs(K - , N, );
int res = ;
for (auto n : visited) {
if (n < ) return -;
res = max(res, n);
}
return res;
} void dfs(int K, int N, int cost) {
if (visited[K] >= ) {
visited[K] = min(cost, visited[K]);
return;
}
visited[K] = cost;
for (int i = ; i < N; i++) {
if (m[K][i] >= ) dfs(i, N, cost + m[K][i]);
}
}
};
dfs_wa
class Solution {
public:
int networkDelayTime(vector<vector<int>>& times, int N, int K) {
if (N < ) return ;
vector<int> d(N, INT_MAX);
vector<vector<int>> m(N, vector<int>(N, -));
for (auto v : times) m[v[] - ][v[] - ] = v[];
queue<int> q, next;
q.push(K - );
d[K - ] = ;
while (!q.empty()) {
set<int> s;
while (!q.empty()) {
int u = q.front(); q.pop();
for (int v = ; v < N; v++) {
if (m[u][v] >= && d[u] + m[u][v] < d[v]) {
if (s.find(v) == s.end()) {
s.insert(v);
next.push(v);
}
d[v] = d[u] + m[u][v];
}
}
}
swap(q, next);
}
int res = ;
for (auto n : d) res = max(n, res);
return res == INT_MAX ? - : res;
}
};
BFS
class Solution {
public:
int networkDelayTime(vector<vector<int>>& times, int N, int K) {
if (N < ) return ;
set<int> visited;
map<int, map<int, int>> graph;
for (auto v : times) graph[v[]][v[]] = v[];
vector<int> dis(N + , INT_MAX);
dis[K] = ;
int pre = K;
while (pre > ) {
visited.insert(pre);
for (auto p : graph[pre]) dis[p.first] = min(dis[p.first], dis[pre] + p.second);
int minNode = -;
for (int i = ; i <= N; i++) {
if (visited.find(i) == visited.end()) {
if (minNode > ) minNode = dis[minNode] > dis[i] ? i : minNode;
else minNode = i;
}
}
pre = minNode;
}
int res = ;
for (int i = ; i <= N; i++) res = max(res, dis[i]);
return res == INT_MAX ? - : res;
}
};
dijkstra
542. 01 Matrix
https://leetcode.com/problems/01-matrix/description/
Given a matrix consists of and , find the distance of the nearest for each cell. The distance between two adjacent cells is .
Example :
Input: Output: Example :
Input: Output: Note:
The number of elements of the given matrix will not exceed ,.
There are at least one in the given matrix.
The cells are adjacent in only four directions: up, down, left and right.
一刷使用朴素的BFS一次AC,二刷加了一点trick,in-place的方式,题目要找到所有格到0格的最短距离,从0格出发不断修改到达非0格的距离,这种转换在DFS和BFS类的题目中非常常见!时间复杂度??
class Solution {
public:
vector<vector<int>> updateMatrix(vector<vector<int>>& matrix) {
int bias[] = {, , , -, };
vector<vector<int>> res(matrix.size(), vector<int>(matrix[].size(), ));
for (int i = ; i < matrix.size(); i++) {
for (int j = ; j < matrix[i].size(); j++) {
bfs(matrix, i, j, res, bias);
}
}
return res;
} void bfs(vector<vector<int>>& matrix, int i, int j, vector<vector<int>>& res, int* bias) {
queue<pair<int, int>> q, next;
q.push(make_pair(i, j));
int layer = ;
while (!q.empty()) {
while (!q.empty()) {
auto p = q.front();
q.pop();
if (!matrix[p.first][p.second]) {
res[i][j] = layer;
return;
} else {
for (int k = ; k < ; k++) {
int r = p.first + bias[k], c = p.second + bias[k + ];
if (r >= && c >= && r < matrix.size() && c < matrix[].size()) next.push(make_pair(r, c));
}
}
}
swap(q, next);
layer++;
}
}
};
my_naive_bfs
class Solution {
public:
vector<vector<int>> updateMatrix(vector<vector<int>>& matrix) {
int m = matrix.size(), n = matrix[].size(), bias[] = {, , , -, };
queue<pair<int, int>> q;
for (int i = ; i < m; i++) {
for (int j = ; j < n; j++) {
if (matrix[i][j]) matrix[i][j] = INT_MAX;
else q.push(make_pair(i, j));
}
}
while (!q.empty()) {
auto p = q.front();
q.pop();
for (int k = ; k < ; k++) {
int r = p.first + bias[k], c = p.second + bias[k + ];
if (r < || r >= m || c < || c >= n || matrix[r][c] < matrix[p.first][p.second] + ) continue;
q.push(make_pair(r, c));
matrix[r][c] = matrix[p.first][p.second] + ;
}
}
return matrix;
}
};
efficient_bfs
30. Substring with Concatenation of All Words
https://leetcode.com/problems/substring-with-concatenation-of-all-words/description/
一刷先用KMP得到每个关键字在母串中出现的所有位置,然后使用DFS得到解,这种方式会超时。二刷使用TP,使用两个map,一个map记录每个模式串的个数,另一个用于匹配,两层循环,外循环遍历母串(注意遍历的范围是0~ss - ws * l),内循环进行匹配,每次匹配都从母串中取出长为l的子串,看是否在map中,在map中则修改map,知道map为空,这时产生了一个答案,继续外循环即可。
class Solution {
public:
vector<int> findSubstring(string s, vector<string>& words) {
unordered_map<string, int> m, copy;
for (string word : words) m[word]++;
vector<int> res;
if (words.size() == ) return res;
int l = words[].size(), ss = s.size(), ws = words.size();
for (int i = ; i <= ss - l * ws; i++) {
unordered_map<string, int> copy(m);
for (int j = ; j < words.size(); j++) {
auto str = s.substr(i + l * j, l);
if (copy.find(str) != copy.end()) {
if (copy[str] == ) copy.erase(str);
else copy[str]--;
if (copy.empty()) {
res.push_back(i); break;
}
} else break;
}
}
return res;
}
};
417. Pacific Atlantic Water Flow
https://leetcode.com/problems/pacific-atlantic-water-flow/description/
Given an m x n matrix of non-negative integers representing the height of each unit cell in a continent, the "Pacific ocean" touches the left and top edges of the matrix and the "Atlantic ocean" touches the right and bottom edges. Water can only flow in four directions (up, down, left, or right) from a cell to another one with height equal or lower. Find the list of grid coordinates where water can flow to both the Pacific and Atlantic ocean. Note:
The order of returned grid coordinates does not matter.
Both m and n are less than .
Example: Given the following 5x5 matrix: Pacific ~ ~ ~ ~ ~
~ () *
~ () () *
~ () *
~ () () *
~ () *
* * * * * Atlantic Return: [[, ], [, ], [, ], [, ], [, ], [, ], [, ]] (positions with parentheses in above matrix).
一刷使用相反的方式,从内到外查看一个节点是否能到达P或者A,终止条件不对,debug很久。二刷使用由外到内的方式,没理解终止条件中的mark参数的意义。
class Solution {
public:
vector<pair<int, int>> res;
int m, n;
vector<vector<int>> visited;
vector<pair<int, int>> pacificAtlantic(vector<vector<int>>& matrix) {
res.resize();
m = matrix.size();
if (m < ) return res;
n = matrix[].size();
visited.resize(m, vector<int>(n ,));
for (int i = ; i< m; i++) {
dfs(i, , matrix, INT_MIN, );
dfs(i, n - , matrix, INT_MIN, );
}
for (int j = ; j < n; j++) {
dfs(, j, matrix, INT_MIN, );
dfs(m - , j, matrix, INT_MIN, );
}
return res;
} void dfs(int i, int j, vector<vector<int>>& matrix, int preHeight, int mark){
if (i < || i >= m || j < || j >= n || matrix[i][j] < preHeight || (mark & visited[i][j]) == mark) return;
visited[i][j] |= mark;
if (visited[i][j] == ) res.push_back(make_pair(i, j));
int bias[] = {, , , -, };
for (int k = ; k < ; k++) {
int r = i + bias[k], c = j + bias[k + ];
dfs(r, c, matrix, matrix[i][j], visited[i][j]);
}
}
};
209. Minimum Size Subarray Sum
https://leetcode.com/problems/minimum-size-subarray-sum/
一开始把题目意思理解错了,浪费了很多时间。subarray是原array的连续子序列,就像substring是原string的连续子序列一样。基于错误的理解,我使用dfs来解决,后来超时才反应过来。一定要好好看题,正确理解题意,往往事半功倍!正确地理解了题意之后,一刷很快ac。二刷更新min_size时没有判别,代码有小幅更新(能用while就不要用for)。
用sum和left记录当前subarray的和与起始位置,注意同时更新sum和left,每次更新min_size之前需要对当前subarray的size进行判别。
class Solution {
public:
int minSubArrayLen(int s, vector<int>& nums) {
long min_size = LONG_MAX;
int left = , sum = ;
for (int i = ; i < nums.size(); i++) {
sum += nums[i];
if (sum >= s) {
while(sum - nums[left] >= s) {
sum -= nums[left];
left ++;
}
if (i - left + < min_size) {
min_size = i - left + ;
}
// cout << min_size << " " << i << endl;
}
}
return min_size == LONG_MAX ? : min_size;
}
};
162. Find Peak Element
https://leetcode.com/problems/find-peak-element/
一刷使用直接遍历的方法,很笨,写了一半发现可疑从两头一起开始遍历,但是时间复杂度并没有明显改善。二刷使用基于迭代的二分法,二分法的合理性感觉可以用罗尔定理证明。变量名写错,mid的判断条件写错。
以后就把自己的二分法固定下来,while里面填low < high, 更新方式为high = mid, low = mid + 1, 返回low。这样以来,写代码的时候实际要判断的只有更新条件了!
class Solution {
public:
int findPeakElement(vector<int>& nums) {
int low = , high = nums.size() - ;
while (low < high) {
int mid = low + (high - low) / ;
if (nums[mid] > nums[mid + ]) {
high = mid;
} else {
low = mid + ;
}
}
return low;
}
};
二分法还可以用递归的方式表现。
class Solution {
public:
int findPeakElement(vector<int>& nums) {
return helper(nums, , nums.size() - );
} int helper(vector<int>& nums, int low, int high) {
if (low == high) {
return low;
} else {
int mid = low + (high - low) / ;
if (nums[mid] > nums[mid + ]) {
return helper(nums, low, mid);
} else {
return helper(nums, mid + , high);
}
}
}
};
recursion
154. Find Minimum in Rotated Sorted Array II
https://leetcode.com/problems/find-minimum-in-rotated-sorted-array-ii/
原来algorithm库中是有min(max)函数的,也有min(max)_element函数的!但是min(max)函数只接受两个参数,没什么实用价值,min(max)_element函数也没什么大的使用价值,返回迭代器。
其实比较简单,一刷一次ac。说实在的,自己被这个hard标志吓得不轻。
class Solution {
public:
int findMin(vector<int>& nums) {
for (int i = ; i < nums.size() - ; i++) {
if (nums[i] > nums[i + ]) {
return nums[i + ];
}
}
return nums[];
}
};
153. Find Minimum in Rotated Sorted Array
https://leetcode.com/problems/find-minimum-in-rotated-sorted-array/
和154一模一样。
152. Maximum Product Subarray
https://leetcode.com/problems/maximum-product-subarray/
原理是dp,但是我对dp并不熟!关键在于当前的max和min并不是全局的max和min,每遍历一个元素就要更新全局的max(res)。一刷变量名写错,效率也不高。二刷由于不理解DP,更新过程写错!三刷一次AC。
class Solution {
public:
int maxProduct(vector<int>& nums) {
int max_pro = nums[], min_pro = nums[], res = nums[];
int a, b;
for (int i = ; i < nums.size(); i ++) {
a = nums[i] * max_pro;
b = nums[i] * min_pro;
max_pro = max(nums[i], max(a, b));
min_pro = min(nums[i], min(a, b));
res = max(res, max_pro);
}
return res;
}
};
344. Reverse String
https://leetcode.com/problems/reverse-string/
字符串翻转,很简单。使用内置函数swap简化了代码,一次AC。
class Solution {
public:
string reverseString(string s) {
int i = , j = s.size() - ;
while (i < j) {
swap(s[i++], s[j--]);
}
return s;
}
};
136. Single Number
https://leetcode.com/problems/single-number/
位运算(异或)经典题目。想象一个多层公寓,每个公寓住着0或者1,异或像如来神掌一样将每一位从上而下压缩。
class Solution {
public:
int singleNumber(vector<int>& nums) {
int n = nums.size();
for (int i = ; i < n; i++) nums[i] = nums[i] ^ nums[i - ];
return nums[n - ];
}
};
137. Single Number II
https://leetcode.com/problems/single-number-ii/description/
Given an array of integers, every element appears three times except for one, which appears exactly once. Find that single one. Note:
Your algorithm should have a linear runtime complexity. Could you implement it without using extra memory?
每一位都有规律,仍然可以按照上题的思路思考,每一位上都是这样的规律sum = x_1 * 3 + x_2 * 3 + ... + x_n-1 * 3 + y,要得到y对sum模3即可。
class Solution {
public:
int singleNumber(vector<int>& nums) {
int res = ;
for (int i = ; i < ; i++) {
int bit_sum = ;
for (int n : nums) {
bit_sum += (n >> i & );
}
res |= ((bit_sum % ) << i);
}
return res;
}
};
260. Single Number III
https://leetcode.com/problems/single-number-iii/description/
Given an array of numbers nums, in which exactly two elements appear only once and all the other elements appear exactly twice. Find the two elements that appear only once. For example: Given nums = [, , , , , ], return [, ]. Note:
The order of the result is not important. So in the above example, [, ] is also correct.
Your algorithm should run in linear runtime complexity. Could you implement it using only constant space complexity?
位操作,按第一个不同的位将nums分为两派即可。思路同前两道题。
class Solution {
public:
vector<int> singleNumber(vector<int>& nums) {
int diff = ;
for (int n : nums) diff ^= n;
diff &= -diff;
vector<int> res();
for (int n : nums) {
if ((n & diff) == ) res[] ^= n;
else res[] ^= n;
}
return res;
}
};
461. Hamming Distance
https://leetcode.com/problems/hamming-distance/description/
The Hamming distance between two integers is the number of positions at which the corresponding bits are different. Given two integers x and y, calculate the Hamming distance. Note:
≤ x, y < . Example: Input: x = , y = Output: Explanation:
( )
( )
↑ ↑ The above arrows point to positions where the corresponding bits are different.
位运算,与和异或。
class Solution {
public:
int hammingDistance(int x, int y) {
int res = ;
for (int i = ; i < ; i++) {
res += ((x >> i) & ) ^ ((y >> i) & );
}
return res;
}
};
477. Total Hamming Distance
https://leetcode.com/problems/total-hamming-distance/description/
The Hamming distance between two integers is the number of positions at which the corresponding bits are different. Now your job is to find the total Hamming distance between all pairs of the given numbers. Example:
Input: , , Output: Explanation: In binary representation, the is , is , and is (just
showing the four bits relevant in this case). So the answer will be:
HammingDistance(, ) + HammingDistance(, ) + HammingDistance(, ) = + + = .
Note:
Elements of the given array are in the range of to ^
Length of the array will not exceed ^.
位运算,分两派,该位为0和该位为1,分别记录每派的count,相乘加到结果上即可。
class Solution {
public:
int totalHammingDistance(vector<int>& nums) {
int res = ;
for (int i = ; i < ; i++) {
int c0 = , c1 = ;
for (int n : nums) {
n >> i & ? c1++ : c0++;
}
res += c0 * c1;
}
return res;
}
};
201. Bitwise AND of Numbers Range
https://leetcode.com/problems/bitwise-and-of-numbers-range/description/
Given a range [m, n] where <= m <= n <= , return the bitwise AND of all numbers in this range, inclusive. For example, given the range [, ], you should return .
位运算
class Solution {
public:
int rangeBitwiseAnd(int m, int n) {
int res = ;
for (int i = ; i < ; i++) {
int tmp = ;
for (int j = ; j < i; j++) {
tmp = (tmp << | );
}
for (int j = i + ; j < ; j++) {
tmp |= ((n >> j & ) << j);
}
if (m > tmp) {
res |= ( << i);
}
}
return res;
}
};
190. Reverse Bits
https://leetcode.com/problems/reverse-bits/description/
Reverse bits of a given bits unsigned integer. For example, given input (represented in binary as ), return (represented in binary as ). Follow up:
If this function is called many times, how would you optimize it? Related problem: Reverse Integer
位运算。一刷边界设置错误没AC。
class Solution {
public:
uint32_t reverseBits(uint32_t n) {
uint32_t res = ;
for (int i = ; i < ; i++) {
res = (res << ) + (n >> i & );
}
return res;
}
};
405. Convert a Number to Hexadecimal
https://leetcode.com/problems/convert-a-number-to-hexadecimal/description/
Given an integer, write an algorithm to convert it to hexadecimal. For negative integer, two’s complement method is used. Note: All letters in hexadecimal (a-f) must be in lowercase.
The hexadecimal string must not contain extra leading 0s. If the number is zero, it is represented by a single zero character ''; otherwise, the first character in the hexadecimal string will not be the zero character.
The given number is guaranteed to fit within the range of a -bit signed integer.
You must not use any method provided by the library which converts/formats the number to hex directly.
Example : Input: Output:
"1a"
Example : Input:
- Output:
"ffffffff"
位运算,注意0的问题,算术右移和逻辑右移的区别。
class Solution {
public:
string toHex(int num) {
string s;
for (int i = ; i < && num; i++) {
int n = ;
for (int j = ; j < ; j++) {
n += (num & ) << j;
num = num >> ;
}
s += n > ? ('a' + n - ) : ('' + n);
}
reverse(s.begin(), s.end());
return s.size() == ? "" : s;
}
};
421. Maximum XOR of Two Numbers in an Array
https://leetcode.com/problems/maximum-xor-of-two-numbers-in-an-array/description/
Given a non-empty array of numbers, a0, a1, a2, … , an-, where ≤ ai < . Find the maximum result of ai XOR aj, where ≤ i, j < n. Could you do this in O(n) runtime? Example: Input: [, , , , , ] Output: Explanation: The maximum result is ^ = .
位运算比较难的题,没太明白关键一步异或的操作的含义。再刷。
class Solution {
public:
int findMaximumXOR(vector<int>& nums) {
int mask = , res = , tmp = ;
set<int> s;
for (int i = ; i >= ; i--) {
mask |= ( << i);
for (int n : nums) s.insert(n & mask);
tmp = res | ( << i);
for (auto i = s.begin(); i != s.end(); i++) {
if (s.find((*i) ^ tmp) != s.end()) {
res = tmp;
break;
}
}
s.clear();
}
return res;
}
};
7. Reverse Integer
https://leetcode.com/problems/reverse-integer/description/
Given a -bit signed integer, reverse digits of an integer. Example : Input:
Output:
Example : Input: -
Output: -
Example : Input:
Output:
Note:
Assume we are dealing with an environment which could only hold integers within the -bit signed integer range. For the purpose of this problem, assume that your function returns when the reversed integer overflows.
和190相似,一刷没AC。注意考虑极限情况,包括INT_MAX和INT_MIN。
class Solution {
public:
int reverse(int x) {
int res = ;
if (x == INT_MIN) return res;
int tmp = abs(x);
while (tmp) {
res = (res * ) + (tmp % );
tmp /= ;
if ((res > INT_MAX / && tmp) || (res == INT_MAX / && tmp > && x > ) || (res == INT_MAX / && tmp > && res < )) return ;
}
return x < ? -res : res;
}
};
476. Number Complement
https://leetcode.com/problems/number-complement/description/
Given a positive integer, output its complement number. The complement strategy is to flip the bits of its binary representation. Note:
The given integer is guaranteed to fit within the range of a -bit signed integer.
You could assume no leading zero bit in the integer’s binary representation.
Example :
Input:
Output:
Explanation: The binary representation of is (no leading zero bits), and its complement is . So you need to output .
Example :
Input:
Output:
Explanation: The binary representation of is (no leading zero bits), and its complement is . So you need to output .
位运算,求补码,从符号位开始0变为1,然后取反。
class Solution {
public:
int findComplement(int num) {
int res = , i = ;
while (i >= && (num >> i & ) == ) {
res |= << i;
i--;
}
while (i >= ) {
res |= (num >> i & ) << i;
i--;
}
return ~res;
}
};
342. Power of Four
https://leetcode.com/problems/power-of-four/description/
Given an integer (signed bits), write a function to check whether it is a power of . Example:
Given num = , return true. Given num = , return false. Follow up: Could you solve it without loops/recursion?
位运算,搞了很久,没抓住主要性质。
class Solution {
public:
bool isPowerOfFour(int num) {
if (num <= ) return false;
if ((num & (-num)) != num) return false;
int i = ;
while (i < ) {
if (num >> i & ) break;
i++;
}
return i % == ;
}
};
class Solution {
public:
bool isPowerOfFour(int num) {
if (num <= ) return false;
if ((num & (-num)) != num) return false;
return (num & (-num)) & 0x55555555;
}
};
no_loop
318. Maximum Product of Word Lengths
https://leetcode.com/problems/maximum-product-of-word-lengths/description/
Given a string array words, find the maximum value of length(word[i]) * length(word[j]) where the two words do not share common letters. You may assume that each word will contain only lower case letters. If no such two words exist, return . Example :
Given ["abcw", "baz", "foo", "bar", "xtfn", "abcdef"]
Return
The two words can be "abcw", "xtfn". Example :
Given ["a", "ab", "abc", "d", "cd", "bcd", "abcd"]
Return
The two words can be "ab", "cd". Example :
Given ["a", "aa", "aaa", "aaaa"]
Return
No such pair of words.
位运算,一刷做的不是最优解!
class Solution {
private:
int get_count(int x) {
int c = ;
for (int i = ; i < ; i++) {
c += ((x >> i) & );
}
return c;
}
public:
int maxProduct(vector<string>& words) {
map<string, pair<int, int>> m;
for (string word : words) {
if (m.find(word) == m.end()) {
int e = ;
for (char c: word) {
e |= << (c - 'a');
}
m[word] = make_pair(e, get_count(e));
}
}
int res = ;
for (int i = ; i < words.size(); i++) {
for (int j = i + ; j < words.size(); j++) {
auto p1 = m[words[i]], p2 = m[words[j]];
int s1 = words[i].size(), s2 = words[j].size();
if (get_count(p1.first ^ p2.first) == p1.second + p2.second) {
res = max(res, s1 * s2);
}
}
}
return res;
}
};
104. Maximum Depth of Binary Tree
https://leetcode.com/problems/maximum-depth-of-binary-tree/
一刷使用层序遍历(BFS),一次AC,效率不高。二刷使用DFS,一行解决问题,效率也非常高,一次AC。
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
int maxDepth(TreeNode* root) {
return (! root) ? : max(maxDepth(root->left), maxDepth(root->right)) + ;
}
};
DFS
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
int maxDepth(TreeNode* root) {
if (! root) {
return ;
} else {
int res = ;
queue<TreeNode*> q;
q.push(root);
int s = q.size();
while (! q.empty()) {
TreeNode* f = q.front();
if (f->left) {
q.push(f->left);
}
if (f->right) {
q.push(f->right);
}
q.pop();
s--;
if (s == ) {
res++;
s = q.size();
}
}
return res;
} }
};
BFS
389. Find the Difference
https://leetcode.com/problems/find-the-difference/
对于字符串的常用方法,将字符转为数组下表,从而将空间复杂度降到O(N)。二刷一次AC。
class Solution {
public:
char findTheDifference(string s, string t) {
char res;
vector<int> s_vec(, );
vector<int> t_vec(, );
for (auto c: s) {
s_vec[c - 'a'] ++;
}
for (auto c: t) {
t_vec[c - 'a'] ++;
}
for (int i = ; i < ; i++) {
if (s_vec[i] != t_vec[i]) {
res = i + 'a';
break;
}
}
return res;
}
};
226. Invert Binary Tree
https://leetcode.com/problems/invert-binary-tree/
使用递归,较简单,二刷一次AC。
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
TreeNode* invertTree(TreeNode* root) {
if (root) {
if (root->left) {
invertTree(root->left);
}
if (root->right) {
invertTree(root->right);
}
swap(root->left, root->right);
}
return root;
}
};
169. Majority Element
https://leetcode.com/problems/majority-element/
二刷使用BM投票算法,因为初始化错误没能AC,深层原因在于没能透彻理解BM算法。
class Solution {
public:
int majorityElement(vector<int>& nums) {
int counter = , major = ;
for (auto n : nums) {
if (counter == ) {
major = n;
}
if (n == major) {
counter ++;
} else {
counter --;
}
}
return major;
}
};
100. Same Tree
https://leetcode.com/problems/same-tree/
使用递归,教简单,二刷改善了codestyle,逻辑也更清晰,一次AC。
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
bool isSameTree(TreeNode* p, TreeNode* q) {
if (! p && ! q) {
return true;
} else if (p && q && p->val == q->val) {
return isSameTree(p->left, q->left) && isSameTree(p->right, q->right);
} else {
return false;
}
}
};
128. Longest Consecutive Sequence
https://leetcode.com/problems/longest-consecutive-sequence/
HashMap,空间换时间。可以使用师姐的思路,每次遇到没访问过的元素,访问之,并查看该元素所在最长连续序列的长度,更新结果,O(N^2)。使用unordered_map记录访问元素的最大长度。当n-1和n+1都访问过后,将序列两端的元素对应的最大长度更新。因为之后序列内部的元素就不考虑了,只会考虑序列外的元素,而序列外的元素跟该序列可能链接的地方只有左右两端,这个题很像DP,注意要将该元素设为访问过的状态,要向map中添加pair,O(N)。
class Solution {
public:
int longestConsecutive(vector<int>& nums) {
unordered_set<int> s(nums.begin(), nums.end());
int length = ;
for (auto i = s.begin(); i != s.end(); i++) {
if (s.find(*i - ) == s.end()) {
int end = *i + ;
while(s.find(end) != s.end()) {
end++;
}
length = max(length, end - *i);
}
}
return length;
}
};
class Solution {
public int longestConsecutive(int[] nums) {
int res = 0;
HashMap<Integer, Integer> m = new HashMap<>();
for (int n: nums) {
if (!m.containsKey(n)) {
int left = m.containsKey(n - 1) ? m.get(n - 1) : 0;
int right = m.containsKey(n + 1) ? m.get(n + 1) : 0;
int sum = left + right + 1;
m.put(n, 1); // put就行,表示访问过,具体的值不care,因为用不到!
res = Math.max(res, sum);
m.put(n - left, sum);
m.put(n + right, sum);
}
}
return res;
}
}
O(N)
126. Word Ladder II
https://leetcode.com/problems/word-ladder-ii/
Given two words (beginWord and endWord), and a dictionary's word list, find all shortest transformation sequence(s) from beginWord to endWord, such that: Only one letter can be changed at a time
Each transformed word must exist in the word list. Note that beginWord is not a transformed word.
For example, Given:
beginWord = "hit"
endWord = "cog"
wordList = ["hot","dot","dog","lot","log","cog"]
Return
[
["hit","hot","dot","dog","cog"],
["hit","hot","lot","log","cog"]
]
prublem desc
BFS和DFS。先用BFS生成每个次到其前缀的map(string, set<string>),利用这个map使用DFS生成所有路径,vector前向插入不便的情景可以使用list。
class Solution {
public:
vector<vector<string>> findLadders(string beginWord, string endWord, vector<string>& wordList) {
unordered_set<string> dict(wordList.begin(), wordList.end()), visit;
queue<string> q, next;
map<string, set<string>> word2forward;
vector<vector<string>> res;
list<string> path;
bool found = false;
q.push(beginWord);
while (!q.empty()) {
while (!q.empty()) {
string cur = q.front(); q.pop();
for (int i = ; i < cur.size(); i++) {
for (int j = ; j < ; j++) {
if ('a' + j != cur[i]) {
string tmp(cur); tmp[i] = 'a' + j;
if (tmp == endWord) found = true;
if (dict.find(tmp) != dict.end()) {
visit.insert(tmp);
word2forward[tmp].insert(cur);
next.push(tmp);
}
}
}
}
}
if (found) break;
for (string s : visit) dict.erase(s);
swap(q, next); visit.clear();
}
dfs(res, path, beginWord, endWord, word2forward);
return res;
} void dfs(vector<vector<string>> &res, list<string> &path, string begin, string end, map<string, set<string>> &word2forward) {
path.push_front(end);
if (end != begin) {
for (string s : word2forward[end]) dfs(res, path, begin, s, word2forward);
} else res.push_back(vector<string>(path.begin(), path.end()));
path.pop_front();
}
};
bfs+dfs
121. Best Time to Buy and Sell Stock
https://leetcode.com/problems/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 :
Input: [, , , , , ]
Output: max. difference = - = (not - = , as selling price needs to be larger than buying price)
Example :
Input: [, , , , ]
Output: In this case, no transaction is done, i.e. max profit = .
prublem desc
比较简单,但是看了一会没什么思路,看了discuss区的答案。思路是遍历每天的股价,记录今日之前的最低价和最高收益,和今日股价比较更新最低价,最高收益和今天卖出的收益比较更新。一刷一次AC,但是思路不是自己的!
class Solution {
public:
int maxProfit(vector<int>& prices) {
int minCur = INT_MAX, maxPro = ;
for (int price: prices) {
minCur = min(minCur, price);
maxPro = max(maxPro, price - minCur);
}
return maxPro;
}
};
122. Best Time to Buy and Sell Stock II
Say you have an array for which the ith element is the price of a given stock on day i. Design an algorithm to find the maximum profit. You may complete as many transactions as you like (ie, buy one and sell one share of the stock multiple times). However, you may not engage in multiple transactions at the same time (ie, you must sell the stock before you buy again).
贪心算法或DP。贪心算法不涨就买,涨就卖。DP使用sell和buy两个数组分别记录当天买入或卖出可能的最大收益,递推公式为:
sell[i] = max(sell[i-1], buy[i-1] + prices[i])
buy[i] = max(buy[i-1], sell[i-1] - prices[i])
class Solution {
public:
int maxProfit(vector<int>& prices) {
int profit = ;
for (int i = ; i < prices.size(); i++) {
if (prices[i] - prices[i - ] > ) profit += prices[i] - prices[i - ];
}
return profit;
}
};
greedy
class Solution {
public:
int maxProfit(vector<int>& prices) {
int m = prices.size();
vector<int> buy(m + ), sell(m + );
buy[] = INT_MIN;
for (int i = ; i <= m; i++) {
sell[i] = max(sell[i - ], buy[i - ] + prices[i - ]);
buy[i] = max(buy[i - ], sell[i - ] - prices[i - ]);
}
return max(buy[m], sell[m]);
}
};
dp
123. Best Time to Buy and Sell Stock III
Say you have an array for which the ith element is the price of a given stock on day i. Design an algorithm to find the maximum profit. You may complete at most two transactions. Note:
You may not engage in multiple transactions at the same time (ie, you must sell the stock before you buy again).
DP。同122,只是要用四个变量分别记录买1次,买2次,卖1次和卖2次的最大收益。
sell2[i] = max(sell[i-1], buy2[i-1] + prices[i])
buy2[i] = max(buy2[i], sell1[i-1] - prices[i])
sell1[i] = max(sell[i-1], buy1[i] + prices[i])
buy1[i] = max(buy1[i-1], -prices[i])
class Solution {
public:
int maxProfit(vector<int>& prices) {
int hold1 = INT_MIN, hold2 = INT_MIN, release1 = , release2 = ;
for (int p : prices) {
release2 = max(release2, hold2 + p);
hold2 = max(hold2, release1 - p);
release1 = max(release1, hold1 + p);
hold1 = max(hold1, -p);
}
return release2;
}
};
dp
120. Triangle
https://leetcode.com/problems/triangle/
Given a triangle, find the minimum path sum from top to bottom. Each step you may move to adjacent numbers on the row below. For example, given the following triangle
[
[],
[,],
[,,],
[,,,]
]
The minimum path sum from top to bottom is (i.e., + + + = ).
desc
DP。自底向上,dp[c] = min(dp[c], dp[c+1]) + triangle[r][c],O(N^2)。
class Solution {
public:
int minimumTotal(vector<vector<int>>& triangle) {
int m = triangle.size();
if (m == ) return ;
vector<int> dp(triangle.back());
for (int r = m - ; r > ; r--) {
for (int c = ; c <= r; c++) {
dp[c - ] = min(dp[c - ], dp[c]) + triangle[r - ][c - ];
}
}
return dp[];
}
};
dp
799. Champagne Tower
We stack glasses in a pyramid, where the first row has glass, the second row has glasses, and so on until the 100th row. Each glass holds one cup (250ml) of champagne. Then, some champagne is poured in the first glass at the top. When the top most glass is full, any excess liquid poured will fall equally to the glass immediately to the left and right of it. When those glasses become full, any excess champagne will fall equally to the left and right of those glasses, and so on. (A glass at the bottom row has it's excess champagne fall on the floor.) For example, after one cup of champagne is poured, the top most glass is full. After two cups of champagne are poured, the two glasses on the second row are half full. After three cups of champagne are poured, those two cups become full - there are full glasses total now. After four cups of champagne are poured, the third row has the middle glass half full, and the two outside glasses are a quarter full, as pictured below. Now after pouring some non-negative integer cups of champagne, return how full the j-th glass in the i-th row is (both i and j are indexed.) Example :
Input: poured = , query_glass = , query_row =
Output: 0.0
Explanation: We poured cup of champange to the top glass of the tower (which is indexed as (, )). There will be no excess liquid so all the glasses under the top glass will remain empty. Example :
Input: poured = , query_glass = , query_row =
Output: 0.5
Explanation: We poured cups of champange to the top glass of the tower (which is indexed as (, )). There is one cup of excess liquid. The glass indexed as (, ) and the glass indexed as (, ) will share the excess liquid equally, and each will get half cup of champange. Note: poured will be in the range of [, ^ ].
query_glass and query_row will be in the range of [, ].
DP。与120类似。
dp[r][c] = (dp[r-1][c-1] >= 1 : dp[r-1][c-1] - 1 : 0) / 2 + (dp[r-1][c] >= 1 ? dp[r-1][c] - 1 : 0) / 2。
class Solution {
public:
double champagneTower(int poured, int query_row, int query_glass) {
vector<double> cur(, poured), next();
bool all_zero = false;
while (query_row-- && !all_zero) {
all_zero = true;
next[] = cur[] > ? (cur[] - ) / : ;
if (next[] > ) all_zero = false;
for (int i = ; i < next.size(); i++) {
next[i] = (cur[i - ] > ? (cur[i - ] - ) / : ) + (cur[i] > ? (cur[i] - ) / : );
if (next[i] > ) all_zero = false;
}
next.push_back(cur[next.size() - ] > ? (cur[next.size() - ] - ) / : );
if (next.back() > ) all_zero = false;
cur = next;
}
if (query_row > && all_zero || query_glass >= cur.size()) return ;
return cur[query_glass] >= ? : cur[query_glass];
}
};
106. Construct Binary Tree from Inorder and Postorder Traversal
https://leetcode.com/problems/construct-binary-tree-from-inorder-and-postorder-traversal/
Given inorder and postorder traversal of a tree, construct the binary tree.
You may assume that duplicates do not exist in the tree.
desc
非递归算法难一点。
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
if (inorder.size() == ) {
return NULL;
} TreeNode * root = new TreeNode(postorder.back());
if (inorder.size() == ) {
return root;
} TreeNode * p;
stack<TreeNode *> s;
s.push(root);
postorder.pop_back(); while () {
if (inorder.back() == s.top()->val) {
p = s.top();
s.pop();
inorder.pop_back(); if (inorder.size() == ) {
break;
} if (s.size() && inorder.back() == s.top()->val) {
continue;
} p->left = new TreeNode(postorder.back());
postorder.pop_back();
s.push(p->left);
} else {
p = new TreeNode(postorder.back());
postorder.pop_back();
s.top()->right = p;
s.push(p);
}
}
return root;
}
};
递归。
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
if (inorder.size() == ) {
return NULL;
}
if (inorder.size() == ) {
return new TreeNode(inorder.back());
}
map<int, int> value2index;
for (int i = ; i < inorder.size(); i++) {
value2index[inorder[i]] = i;
}
return buildTree(inorder, , inorder.size() - , postorder, , postorder.size() - , value2index);
} TreeNode* buildTree(vector<int>& inorder, int in_start, int in_end, vector<int>& postorder, int post_start, int post_end, map<int, int> & v2i) {
if (in_start > in_end || post_start > post_end) {
return NULL;
}
TreeNode * root = new TreeNode(postorder[post_end]);
int root_index = v2i[root->val];
root->left = buildTree(inorder, in_start, root_index - , postorder, post_start, post_start + root_index - in_start - , v2i);
root->right = buildTree(inorder, root_index + , in_end, postorder, post_start + root_index - in_start, post_end - , v2i);
return root;
}
};
recursion
105. Construct Binary Tree from Preorder and Inorder Traversal
https://leetcode.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/
Given preorder and inorder traversal of a tree, construct the binary tree. Note:
You may assume that duplicates do not exist in the tree.
desc
递归。同106,由于树中无重复元素,可以用map记录inorder中元素到index的映射,这样就不用在生成树时遍历inorder查找元素了,这样可以把时间复杂度降为O(N^2)。
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
if (inorder.size() == ) {
return NULL;
}
if (inorder.size() == ) {
return new TreeNode(inorder[]);
}
map<int, int> value2index;
for (int i = ; i < inorder.size(); i++) {
value2index[inorder[i]] = i;
}
TreeNode * root = buildTree(preorder, , preorder.size() - , inorder, , inorder.size() - , value2index);
return root;
} TreeNode * buildTree(vector<int>& preorder, int pre_start, int pre_end, vector<int>& inorder, int in_start, int in_end, map<int, int>& value2index) {
if (pre_start > pre_end || in_start > in_end) {
return NULL;
}
TreeNode * root = new TreeNode(preorder[pre_start]);
int root_index = value2index[root->val];
root->left = buildTree(preorder, pre_start + , pre_start + root_index - in_start, inorder, in_start, root_index - , value2index);
root->right = buildTree(preorder, pre_start + root_index - in_start + , pre_end, inorder, root_index + , in_end, value2index);
return root;
}
};
108. Convert Sorted Array to Binary Search Tree
https://leetcode.com/problems/convert-sorted-array-to-binary-search-tree/description/
递归,二分查找。
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
TreeNode* sortedArrayToBST(vector<int>& nums) {
int n = nums.size();
if (n == ) return NULL;
return build(nums, , n - );
}
TreeNode* build(vector<int>& nums, int b, int e) {
if (b > e || b < || e >= nums.size()) return NULL;
int mid = b + ((e - b) >> );
TreeNode* root = new TreeNode(nums[mid]);
root->left = build(nums, b, mid - );
root->right = build(nums, mid + , e);
return root;
}
};
109. Convert Sorted List to Binary Search Tree
https://leetcode.com/problems/convert-sorted-list-to-binary-search-tree/#/description
同108,只是这里mid要通过快慢指针来找。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
TreeNode* sortedListToBST(ListNode* head) {
return dfs(head, NULL);
}
TreeNode* dfs(ListNode* head, ListNode* tail) {
if (head == tail) return NULL;
ListNode *slow = head, *fast = head;
while (fast != tail && fast->next != tail) {
slow = slow->next;
fast = fast->next->next;
}
TreeNode *root = new TreeNode(slow->val);
root->left = dfs(head, slow);
root->right = dfs(slow->next, tail);
return root;
}
};
114. Flatten Binary Tree to Linked List
https://leetcode.com/problems/flatten-binary-tree-to-linked-list/description/
递归,将左右分别flattern之后,将左侧链接到右侧。
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
void flatten(TreeNode* root) {
if (!root || (!root->left && !root->right)) return;
flatten(root->left);
flatten(root->right);
TreeNode* t = root->right;
root->right = root->left;
root->left = NULL;
while (root->right) {
root = root->right;
}
root->right = t;
}
};
78. Subsets
https://leetcode.com/problems/subsets/
Given a set of distinct integers, nums, return all possible subsets. Note: The solution set must not contain duplicate subsets.
desc
一刷由于对vector的一些成员函数不熟悉,没有AC。二刷一次AC。讨论区第一名的算法是基于bitmap做的,一刷由于对vector的多元素版本的构造函数格式不熟,没能AC。二刷一次AC。
class Solution {
public:
vector<vector<int>> subsets(vector<int>& nums) {
vector<int> emptySet();
vector<vector<int>> res = {emptySet};
if (nums.size() == ) {
return res;
}
vector<vector<int>> init(res); while (nums.size() != ) {
int num = nums.back();
nums.pop_back();
init = res;
for (auto s: init) {
s.push_back(num);
res.push_back(s);
}
}
return res;
}
};
class Solution {
public:
vector<vector<int>> subsets(vector<int>& nums) {
vector<int> emp();
// sort(nums.begin(), nums.end());
vector<vector<int>> res(pow(, nums.size()), emp);
for (int i = ; i < nums.size(); i++) {
for (int j = ; j < res.size(); j++) {
if ((j >> i) & ) {
res[j].push_back(nums[i]);
}
}
}
return res;
}
};
Bitmap Code
三刷使用backtracing方法刷这类题,效率无损失。递归参数设置错误得了WA,再刷!四刷使用backtracing,没AC,应该存入第i个元素但是存了第start个元素,这个错误好几次了!
class Solution {
public:
vector<vector<int>> subsets(vector<int>& nums) {
vector<vector<int>> res;
vector<int> tmp;
backtrace(res, tmp, nums, );
return res;
} void backtrace(vector<vector<int>> &res, vector<int> &tmp, vector<int>& nums, int b) {
res.push_back(tmp);
for (int i = b; i < nums.size(); i++) {
tmp.push_back(nums[i]);
backtrace(res, tmp, nums, i+);
tmp.pop_back();
}
}
};
backtrack
75. Sort Colors
https://leetcode.com/problems/sort-colors/
Given an array with n objects colored red, white or blue, sort them so that objects of the same color are adjacent, with the colors in the order red, white and blue. Here, we will use the integers , , and to represent the color red, white, and blue respectively. Note:
You are not suppose to use the library's sort function for this problem.
desc
排序,手写快排、堆排等时间复杂度都是O(NlogN)。
暴力法第一次遍历记录0,1,2的数量,第二次遍历按照数量赋值上去,O(N)。
TP,O(N)。令index_0和index_2分别表示下一个0和2应该填进去的坑,扫一遍数组,将0放在swap到前面,2swap到后面,1自然就被swap到中间了。
变式题:RGB无序序列排成RGBRGB形式的序列,三指针。
class Solution {
public:
void sortColors(vector<int>& nums) {
int n = nums.size(), red_i = , blue_i = n - ;
for (int i = ; i <= blue_i; i++) {
while (nums[i] == && i < blue_i) swap(nums[i], nums[blue_i--]);
while (nums[i] == && i > red_i) swap(nums[i], nums[red_i++]);
}
}
};
two pointers
#include <iostream>
#include <string> using namespace std; string colors = "RRRRGGGGBBBBGRB"; void swapColors(int i, int j);
int getColor(int i);
int main() {
int i = , rIndex = , gIndex = , bIndex = ;
// r/g/bindex分别表示当前放错位置的R,G,B应该放到的最前面的位置。
while (i < colors.size()) {
// 当前格子颜色正确,表明前面的所有格子已经排好序,i向后移动即可。
if (i % == && getColor(i) == 'R') ++i;
else if (i % == && getColor(i) == 'G') ++i;
else if (i % == && getColor(i) == 'B') ++i;
else {
// 当前格子颜色不对, 往后跳格子,将当前颜色挪到正确的格子。
if (getColor(i) == 'R') {
while (rIndex < colors.size() && getColor(rIndex) == 'R') rIndex += ;
if (rIndex < colors.size()) swapColors(i, rIndex);
} else if (getColor(i) == 'G') {
while (gIndex < colors.size() && getColor(gIndex) == 'G') gIndex += ;
if (gIndex < colors.size()) swapColors(i, gIndex);
} else if (getColor(i) == 'B') {
while (bIndex < colors.size() && getColor(bIndex) == 'B') bIndex += ;
if (gIndex < colors.size()) swapColors(i, bIndex);
}
}
}
cout << colors << endl;
} int getColor(int i) {
return colors[i];
} void swapColors(int i, int j) {
swap(colors[i], colors[j]);
}
Sort RGB
74. Search a 2D Matrix
https://leetcode.com/problems/search-a-2d-matrix/?tab=Description
Write an efficient algorithm that searches for a value in an m x n matrix. This matrix has the following properties: Integers in each row are sorted from left to right.
The first integer of each row is greater than the last integer of the previous row.
For example, Consider the following matrix: [
[, , , ],
[, , , ],
[, , , ]
]
Given target = , return true.
desc
BS,将矩阵降为视为一维数组用BS。index的映射关系:matrix[mid / n][mid % n]。
class Solution {
public:
bool searchMatrix(vector<vector<int>>& matrix, int target) {
int m = matrix.size(), n;
if (m == ) return false;
n = matrix[].size();
if (n == ) return false;
int low = , high = n * m - , mid;
while (low < high) {
mid = low + ((high - low) >> );
if (matrix[mid / n][mid % n] < target) low = mid + ;
else high = mid;
}
return matrix[low / n][low % n] == target;
}
};
240. Search a 2D Matrix II
https://leetcode.com/problems/search-a-2d-matrix-ii/description/
math,BS的变形,所选的哨兵为角上的元素,每次将范围缩减一行或一列,O(MAX(M,N))。暴力方法是对每一行进行BS,O(MlogN)。
class Solution {
public:
bool searchMatrix(vector<vector<int>>& matrix, int target) {
for (int i = ; i < matrix.size(); i++) {
auto iter = lower_bound(matrix[i].begin(), matrix[i].end(), target);
if (iter != matrix[i].end() && *iter == target) return true;
}
return false;
}
};
BF
class Solution {
public:
bool searchMatrix(vector<vector<int>>& matrix, int target) {
int m = matrix.size(), n;
if (m == ) return false;
n = matrix[].size();
if (n == ) return false;
int row = , col = n - ;
while (row < m && col >= ) {
int cur = matrix[row][col];
if (cur == target) return true;
else if (cur > target) col--;
else row++;
}
return false;
}
};
more efficient
73. Set Matrix Zeroes
https://leetcode.com/problems/set-matrix-zeroes/?tab=Description
Given a m x n matrix, if an element is , set its entire row and column to . Do it in place.
desc
将第一行和第一列作为标志,元素为0表示相应行或列全部置零,第一列用单独的标志。顺序遍历将标志置0,逆序遍历按标志将元素置0。
void setZeroes(vector<vector<int>>& matrix) {
int m = matrix.size();
if (m == ) return;
int n = matrix[].size();
if (n == ) return;
int col = ;
for (int i = ; i < m; i++) {
if (!matrix[i][]) col = ;
for (int j = ; j < n; j++) {
if (!matrix[i][j]) matrix[i][] = matrix[][j] = ;
}
}
for (int i = m - ; i >= ; i--) {
for (int j = n - ; j > ; j--) {
if (!matrix[i][] || !matrix[][j]) matrix[i][j] = ;
}
if (col == ) matrix[i][] = ;
}
}
64. Minimum Path Sum
https://leetcode.com/problems/minimum-path-sum/?tab=Description
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.
desc
DP。同62。
class Solution {
public:
int minPathSum(vector<vector<int>>& grid) {
int m = grid.size();
if (m == ) return ;
int n = grid[].size();
if (n == ) return ;
vector<int> dp(m);
dp[] = grid[][];
for (int i = ; i < m; i++) dp[i] = dp[i - ] + grid[i][];
for (int j = ; j < n; j++) {
dp[] += grid[][j];
for (int i = ; i < m; i++) dp[i] = min(dp[i], dp[i - ]) + grid[i][j];
}
return dp[m - ];
}
};
62. Unique Paths
https://leetcode.com/problems/unique-paths/?tab=Description
A robot is located at the top-left corner of a m x n grid (marked 'Start' in the diagram below). The robot can only move either down or right at any point in time. The robot is trying to reach the bottom-right corner of the grid (marked 'Finish' in the diagram below). How many possible unique paths are there?
desc
DP。
class Solution {
public:
int uniquePaths(int m, int n) {
if (m < n) return uniquePaths(n, m);
vector<int> dp(m, );
for (int i = ; i < n; i++) {
for (int j = ; j < m; j++) dp[j] += dp[j - ];
}
return dp[m - ];
}
};
1D-DP
63. Unique Paths II
https://leetcode.com/problems/unique-paths-ii/?tab=Description
Follow up for "Unique Paths": Now consider if some obstacles are added to the grids. How many unique paths would there be? An obstacle and empty space is marked as and respectively in the grid. For example,
There is one obstacle in the middle of a 3x3 grid as illustrated below. [
[,,],
[,,],
[,,]
]
The total number of unique paths is .
desc
DP,同62.
class Solution {
public:
int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid) {
int m = obstacleGrid.size(), n;
if (m == ) return ;
n = obstacleGrid[].size();
if (n == ) return ;
vector<int> dp(m, );
for (int i = ; i < m; i++) {
if (obstacleGrid[i][] == ) dp[i] = ;
else break;
}
for (int j = ; j < n; j++) {
if (obstacleGrid[][j] == ) dp[] = ;
for (int i = ; i < m; i++) dp[i] = obstacleGrid[i][j] == ? : dp[i] + dp[i - ];
}
return dp[m - ];
}
};
1D-DP
53. Maximum Subarray
https://leetcode.com/problems/maximum-subarray/?tab=Description
Find the contiguous subarray within an array (containing at least one number) which has the largest sum. For example, given the array [-,,-,,-,,,-,],
the contiguous subarray [,-,,] has the largest sum = .
DP,可以降为0维DP。累加,当加到a[i]时候如果当前sum小于0。就把[0-i]都扔掉 重新加起。画了个函数图像,感觉稍微好些。序列中的每个数都是sum的导数,这么看的话就可以理解。DP算法好些可以解释连续的问题。和LCS很相似,DP解法构造子问题形式的思路相同,DP[i]表示以[i]结尾的sub序列。
class Solution {
public:
int maxSubArray(vector<int>& nums) {
int res = INT_MIN, sum = ;
for (int n : nums) {
sum += n;
if (sum < n) sum = n;
res= max(sum, res);
}
return res;
}
};
72. Edit Distance
https://leetcode.com/problems/edit-distance/description/
Given two words word1 and word2, find the minimum number of steps required to convert word1 to word2. (each operation is counted as step.) You have the following operations permitted on a word: a) Insert a character
b) Delete a character
c) Replace a character
DP,知道思路,没能将问题降级为子问题。需要继续理解!
class Solution {
public:
int minDistance(string word1, string word2) {
int m = word1.size(), n = word2.size();
vector<vector<int>> dp(m + , vector<int>(n + , ));
for (int i = ; i <= m; i++) dp[i][] = i;
for (int j = ; j <= n; j++) dp[][j] = j;
for (int i = ; i <= m; i++) {
for (int j = ; j <= n; j++) {
if (word1[i - ] == word2[j - ]) dp[i][j] = dp[i - ][j - ];
else dp[i][j] = min(dp[i - ][j - ] + , min(dp[i - ][j] + , dp[i][j - ] + ));
}
}
return dp[m][n];
}
};
486. Predict the Winner
https://leetcode.com/problems/predict-the-winner/description/
Given an array of scores that are non-negative integers. Player picks one of the numbers from either end of the array followed by the player and then player and so on. Each time a player picks a number, that number will not be available for the next player. This continues until all the scores have been chosen. The player with the maximum score wins. Given an array of scores, predict whether player is the winner. You can assume each player plays to maximize his score. Example :
Input: [, , ]
Output: False
Explanation: Initially, player can choose between and .
If he chooses (or ), then player can choose from (or ) and . If player chooses , then player will be left with (or ).
So, final score of player is + = , and player is .
Hence, player will never be the winner and you need to return False.
Example :
Input: [, , , ]
Output: True
Explanation: Player first chooses . Then player have to choose between and . No matter which number player choose, player can choose .
Finally, player has more score () than player (), so you need to return True representing player1 can win.
Note:
<= length of the array <= .
Any scores in the given array are non-negative integers and will not exceed ,,.
If the scores of both players are equal, then player is still the winner.
二维DP,一维亦可,二维DP易于理解。两个维度坐标含义相同,填表方式是沿对角线填表,这取决于子问题的结构。子问题结构比较容易看出来,对于dp[i][j],取头剩dp[i+1][j],取尾剩dp[i][j-1],但是剩下的是对手的盘,因此要将dp中存储的元素设置为一手比二手玩家多得的分,这样对手的盘就是负值!
class Solution {
public:
bool PredictTheWinner(vector<int>& nums) {
int n = nums.size();
if (n < ) return true;
vector<vector<int>> dp(n, vector<int>(n, ));
for (int i = ; i < n; i++) dp[i][i] = nums[i];
for (int len = ; len < n; len++) {
for (int i = ; i + len < n; i++) {
int j = i + len;
dp[i][j] = max(nums[i] - dp[i + ][j], nums[j] - dp[i][j - ]);
}
}
return dp[][n - ] >= ;
}
};
45. Jump Game II
https://leetcode.com/problems/jump-game-ii/description/
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. For example:
Given array A = [,,,,] The minimum number of jumps to reach the last index is . (Jump step from index to , then steps to the last index.) Note:
You can assume that you can always reach the last index.
DP,BFS。DP复杂度为O(N^2),自己写的DP,遍历nums,填充并修改dp,如果dp[i]都有效,遍历[1, nums[i]],更新dp[i+j],这种方式会超时。师姐的dp跟我不太一样,为了得到dp[i],遍历dp[0, i-1],如果一步可以到i则直接跳出,师姐的dp思路才是真正的dp思路。BFS的复杂度为O(N),从0开始,对于每层更新能到达的最远的元素,然后从那个元素开始,直到能够到最后一个元素位置。
class Solution {
public:
int jump(vector<int>& nums) {
int n = nums.size();
vector<int> dp(n, -);
dp[] = ;
for (int i = ; i < n; i++) {
for (int j = ; j < n; j++) {
if (dp[j] >= && j + nums[j] >= i) {
dp[i] = dp[j] + ; break;
}
}
}
return dp[n - ];
}
};
dfs
class Solution {
public:
int jump(vector<int>& nums) {
int n = nums.size();
vector<int> dp(n, -);
dp[] = ;
for (int i = ; i < n; i++) {
for (int j = ; j < n; j++) {
if (dp[j] >= && j + nums[j] >= i) {
dp[i] = dp[j] + ; break;
}
}
}
return dp[n - ];
}
};
dp
55. Jump Game
https://leetcode.com/problems/jump-game/?tab=Description
同45。三种方法,性能由差到好。
54. Spiral Matrix
https://leetcode.com/problems/spiral-matrix/?tab=Description
desc
math。内循环每次从(i,i)开始,向右走到(i, n - i - 1), 再向下走到(m - i - 1, n - i - 1),再向左走到(m - i - 1, i), 最后向上走到(i + 1, i)。注意去重,即后两趟走的不能和前两趟走的不能是一条道。
59. Spiral Matrix II
https://leetcode.com/problems/spiral-matrix-ii/?tab=Description
Given an integer n, generate a square matrix filled with elements from to n2 in spiral order. For example,
Given n = , You should return the following matrix:
[
[ , , ],
[ , , ],
[ , , ]
]
desc
我以为矩阵有两种遍历方式:第一种比第二种更有美感,结果这是个陷阱。
解法同54。
class Solution {
public:
vector<vector<int>> generateMatrix(int n) {
vector<vector<int>> res;
if (n == ) return res;
res.resize(n, vector<int>(n , ));
int i = , num = ;
for (int i = , num = ; i < n - i; i++) {
for (int r = i, c = i; c < n - i; c++) res[r][c] = num++;
for (int r = i + , c = n - i - ; r < n - i; r++) res[r][c] = num++;
for (int r = n - i - , c = n - i - ; c >= i && r > i; c--) res[r][c] = num++;
for (int r = n - i - , c = i; r > i && c < n - i - ; r--) res[r][c] = num++;
}
return res;
}
};
56. Merge Intervals
https://leetcode.com/problems/merge-intervals/?tab=Description
Given a collection of intervals, merge all overlapping intervals. For example,
Given [,],[,],[,],[,],
return [,],[,],[,].
desc
sort的第三个参数为重载了"<"的函数。可以自己写myCompare函数实现"<"逻辑,也可以写函数类用于构建函数对象。也可以利用C++11新特性lambda表达式实现,编译器会根据lambda表达式生成函数对象。
/**
* Definition for an interval.
* struct Interval {
* int start;
* int end;
* Interval() : start(0), end(0) {}
* Interval(int s, int e) : start(s), end(e) {}
* };
*/
class Solution {
public:
vector<Interval> merge(vector<Interval>& intervals) {
if (intervals.size() == ) {
return vector<Interval>();
}
sort(
intervals.begin(),
intervals.end(),
[] (Interval a, Interval b) {return a.start < b.start;});
vector<Interval> res(, intervals[]);
for (int i = ; i < intervals.size(); i++) {
if (res.back().end < intervals[i].start) {
res.push_back(intervals[i]);
} else {
res.back().end = max(res.back().end, intervals[i].end);
}
}
return res;
}
};
overload operator
/**
* Definition for an interval.
* struct Interval {
* int start;
* int end;
* Interval() : start(0), end(0) {}
* Interval(int s, int e) : start(s), end(e) {}
* };
*/
class Solution {
private:
static bool myCompare(Interval a, Interval b) {
return a.start < b.start;
}
public:
vector<Interval> merge(vector<Interval>& intervals) {
int n = intervals.size();
if (n < ) return intervals;
sort(intervals.begin(), intervals.end(), myCompare);
vector<Interval> res(, intervals[]);
for (Interval i : intervals) {
if (i.start > res.back().end) {
res.push_back(i);
} else {
res.back().end = max(res.back().end, i.end);
}
}
return res;
}
};
myCompare
/**
* Definition for an interval.
* struct Interval {
* int start;
* int end;
* Interval() : start(0), end(0) {}
* Interval(int s, int e) : start(s), end(e) {}
* };
*/
class Solution {
public:
vector<Interval> merge(vector<Interval>& intervals) {
vector<Interval> res;
if (intervals.size() == ) return res;
sort(intervals.begin(), intervals.end(), [](const Interval& a, const Interval& b) {return a.start < b.start;});
res.push_back(intervals[]);
for (auto i : intervals) {
if (i.start <= res.back().end) res.back().end = max(i.end, res.back().end);
else res.push_back(i);
}
return res;
}
};
lambda
57. Insert Interval
https://leetcode.com/problems/insert-interval/description/
Given a set of non-overlapping intervals, insert a new interval into the intervals (merge if necessary). You may assume that the intervals were initially sorted according to their start times. Example :
Given intervals [,],[,], insert and merge [,] in as [,],[,]. Example :
Given [,],[,],[,],[,],[,], insert and merge [,] in as [,],[,],[,]. This is because the new interval [,] overlaps with [,],[,],[,].
同56,先将要新Interval插入列表,然后merge。应该有更高效的算法。
/**
* Definition for an interval.
* struct Interval {
* int start;
* int end;
* Interval() : start(0), end(0) {}
* Interval(int s, int e) : start(s), end(e) {}
* };
*/
class Solution {
public:
vector<Interval> insert(vector<Interval>& intervals, Interval newInterval) {
int n = intervals.size();
intervals.push_back(newInterval);
sort(intervals.begin(), intervals.end(), [](Interval a, Interval b) {return a.start < b.start;});
vector<Interval> res(, intervals[]);
for (Interval i : intervals) {
if (res.back().end < i.start) {
res.push_back(i);
} else {
res.back().end = max(res.back().end, i.end);
}
}
return res;
}
};
406. Queue Reconstruction by Height
https://leetcode.com/problems/queue-reconstruction-by-height/description/
Suppose you have a random list of people standing in a queue. Each person is described by a pair of integers (h, k), where h is the height of the person and k is the number of people in front of this person who have a height greater than or equal to h. Write an algorithm to reconstruct the queue. Note:
The number of people is less than ,. Example Input:
[[,], [,], [,], [,], [,], [,]] Output:
[[,], [,], [,], [,], [,], [,]]
sort。使用lambda表达式进行sort,然后将每个元素插到res.begin()+p.second的位置上。
53. Maximum Subarray
https://leetcode.com/problems/maximum-subarray/?tab=Description
Find the contiguous subarray within an array (containing at least one number) which has the largest sum. For example, given the array [-,,-,,-,,,-,],
the contiguous subarray [,-,,] has the largest sum = .
desc
DP,可以降为0维DP。累加,当加到a[i]时候如果当前sum小于0。就把[0-i]都扔掉 重新加起。画了个函数图像,感觉稍微好些。序列中的每个数都是sum的导数,这么看的话就可以理解。DP算法好些可以解释连续的问题。和LCS很相似,DP解法构造子问题形式的思路相同,DP[i]表示以[i]结尾的sub序列。
class Solution {
public:
int maxSubArray(vector<int>& nums) {
int res = INT_MIN, sum = ;
for (int n : nums) {
sum += n;
if (sum < n) sum = n;
res= max(sum, res);
}
return res;
}
};
48. Rotate Image
https://leetcode.com/problems/rotate-image/?tab=Description
You are given an n x n 2D matrix representing an image. Rotate the image by degrees (clockwise). Follow up:
Could you do this in-place?
desc
math。矩阵顺时针旋转,先将矩阵进行上下翻转(上换到下),然后对角互换(左下换到左上),于是左上就换到了右上,左下换到了左上,右上换到了右下,右下换到了左下,实现了顺时针旋转90度。对于逆时针旋转先上下翻转,然后左上与右下互换。
class Solution {
public:
void rotate(vector<vector<int>>& matrix) {
int n = matrix.size();
reverse(matrix.begin(), matrix.end());
for (int i = ; i < n; i++) {
for (int j = i + ; j < n; j++) swap(matrix[i][j], matrix[j][i]);
}
}
};
66. Plus One
https://leetcode.com/problems/plus-one/description/
math。初始化令最低位进位c=1,可以按照统一的模式解决。
class Solution {
public:
vector<int> plusOne(vector<int>& digits) {
int c = , n = digits.size(), s = ;
for (int i = n - ; i >= ; i--) {
s = c + digits[i];
digits[i] = s % ;
c = s / ;
}
if (c > ) {
digits.resize(n + , );
for (int i = n; i > ; i--) digits[i] = digits[i - ];
digits[] = c;
}
return digits;
}
};
40. Combination Sum II
https://leetcode.com/problems/combination-sum-ii/?tab=Description
Given a collection of candidate numbers (C) and a target number (T), find all unique combinations in C where the candidate numbers sums to T. Each number in C 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.
For example, given candidate set [, , , , , , ] and target ,
A solution set is:
[
[, ],
[, , ],
[, ],
[, , ]
]
desc
DFS。首先要排序,之后要对照解空间写递归过程。
class Solution {
public:
vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
sort(candidates.begin(), candidates.end());
vector<vector<int>> res;
vector<int> path;
dfs(candidates, res, path, , target);
return res;
} void dfs(vector<int>& candidates, vector<vector<int>>& res, vector<int>& path, int start, int target) {
if (target == ) res.push_back(path);
if (target <= ) return;
for (int i = start; i < candidates.size(); i++) {
if (i > start && candidates[i] == candidates[i - ]) continue;
path.push_back(candidates[i]);
dfs(candidates, res, path, i + , target - candidates[i]);
path.pop_back();
}
}
};
dfs
39. Combination Sum
https://leetcode.com/problems/combination-sum/?tab=Description
Given a set of candidate numbers (C) (without duplicates) and a target number (T), find all unique combinations in C where the candidate numbers sums to T. The same repeated number may be chosen from C unlimited number of times. Note:
All numbers (including target) will be positive integers.
The solution set must not contain duplicate combinations.
For example, given candidate set [, , , ] and target ,
A solution set is:
[
[],
[, , ]
]
desc
dfs。可以画出解空间来理解解题过程。
class Solution {
public:
vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
vector<vector<int>> res;
vector<int> path;
dfs(res, path, candidates, target, );
return res;
}
void dfs(vector<vector<int>>& res, vector<int>& path, vector<int>& can, int target, int start) {
if (start >= can.size() || target < ) return;
if (target == ) {
res.push_back(path);
return;
}
for (int i = start; i < can.size(); i++) {
path.push_back(can[i]);
dfs(res, path, can, target - can[i], i);
path.pop_back();
}
}
};
35. Search Insert Position
https://leetcode.com/problems/search-insert-position/?tab=Description
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. Here are few examples.
[,,,], →
[,,,], →
[,,,], →
[,,,], →
desc
BS。可以直接用upper_bound或者lower_bound来做。
class Solution {
public:
int searchInsert(vector<int>& nums, int target) {
auto iter = upper_bound(nums.begin(), nums.end(), target);
return iter != nums.begin() && *(iter - ) == target ? iter - nums.begin() - : iter - nums.begin();
}
};
34. Search for a Range
https://leetcode.com/problems/search-for-a-range/?tab=Description
Given an array of integers 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 [-, -]. For example,
Given [, , , , , ] and target value ,
return [, ].
desc
BS。BS查找下界和上界两类问题存在区别,区别在于求下界时mid要靠近low,求上界的时候mid要靠近high;这种区别决定在每次循环更新要找的那个界限(low或者high)。也可以借助STL的upper_bound和lower_bound函数实现。
class Solution {
public:
vector<int> searchRange(vector<int>& nums, int target) {
vector<int> res(, -);
int n = nums.size();
if (n == ) return res;
int low = , high = n - , mid;
while (low < high) {
mid = low + ((high - low) >> );
if (nums[mid] < target) low = mid + ;
else high = mid;
}
res[] = nums[low] == target ? low : -;
low = , high = n - ;
while (low < high) {
mid = low + ((high - low + ) >> );
if (nums[mid] > target) high = mid - ;
else low = mid;
}
res[] = nums[low] == target ? low : -;
return res;
}
};
BS
33. Search in Rotated Sorted Array
https://leetcode.com/problems/search-in-rotated-sorted-array/?tab=Description
Suppose an array sorted in ascending order is rotated at some pivot unknown to you beforehand. (i.e., might become ). You are given a target value to search. If found in the array return its index, otherwise return -. You may assume no duplicate exists in the array.
desc
BS。
class Solution {
public:
int search(vector<int>& nums, int target) {
int s = nums.size(), low, high, mid;
if (s == ) return -;
low = ; high = s - ;
while (low < high) {
mid = low + ((high - low) >> );
if (nums[mid] == target) return mid;
if (nums[low] <= nums[mid]) {
if (nums[mid] > target && nums[low] <= target) high = mid - ;
else low = mid + ;
} else {
if (nums[mid] < target && target <= nums[high]) low = mid + ;
else high = mid - ;
}
}
return nums[low] == target ? low : -;
}
};
81. Search in Rotated Sorted Array II
https://leetcode.com/problems/search-in-rotated-sorted-array-ii/
BS。同33,只是数组中存在重复元素,[mid] = [low]时分类不明显,直接拎出来,令low++(相当于遍历),其余不变。
class Solution {
public:
bool search(vector<int>& nums, int target) {
int s = nums.size(), low = , high = s - , mid;
if (s == ) return false;
while (low < high) {
mid = low + ((high - low) >> );
if (nums[mid] == target) return true;
if (nums[mid] > nums[low]) {
if (nums[low] <= target && nums[mid] > target) high = mid - ;
else low = mid + ;
} else if (nums[mid] < nums[low]) {
if (nums[mid] < target && nums[high] >= target) low = mid + ;
else high = mid - ;
} else low++;
}
return nums[low] == target;
}
};
31. Next Permutation
https://leetcode.com/problems/next-permutation/?tab=Description
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, do not allocate extra memory. Here are some examples. Inputs are in the left-hand column and its corresponding outputs are in the right-hand column.
,, → ,,
,, → ,,
,, → ,,
desc
Math。理解还是不透彻,不知道为什么这么做。
class Solution {
public:
void nextPermutation(vector<int>& nums) {
int n = nums.size(), i;
if (n < ) return;
for (i = n - ; i >= && nums[i] >= nums[i + ]; i--);
reverse(nums.begin() + i + , nums.end());
if (i == -) return;
auto iter = upper_bound(nums.begin() + i + , nums.end(), nums[i]);
swap(nums[i], *iter);
}
};
41. First Missing Positive
https://leetcode.com/problems/first-missing-positive/description/
Given an unsorted integer array, find the first missing positive integer. For example,
Given [,,] return ,
and [,,-,] return . Your algorithm should run in O(n) time and uses constant space.
math。鸽巢原理,第一个missing的正整数的范围一定是[1, array.size() + 1]。扫描原数组,用额外的数组记录已经出现的正整数,再扫描新数组,第一个没访问过的数就是第一个missing的正整数。有更好的方法,不需要额外的空间,详见 http://www.cnblogs.com/AnnieKim/archive/2013/04/21/3034631.html 。
class Solution {
public:
int firstMissingPositive(vector<int>& nums) {
vector<int> v(nums.size() + , );
for (int n : nums) {
if (n > && n <= nums.size()) v[n - ] = ;
}
int i = ;
while (i <= nums.size() && v[i] != ) i++;
return i + ;
}
};
18. 4Sum
https://leetcode.com/problems/4sum/?tab=Description
Given an array S of n integers, are there elements a, b, c, and d in S such that a + b + c + d = target? Find all unique quadruplets in the array which gives the sum of target. Note: The solution set must not contain duplicate quadruplets. For example, given array S = [, , -, , -, ], and target = . A solution set is:
[
[-, , , ],
[-, -, , ],
[-, , , ]
]
desc
双指针。先进行sort,然后逐个确定i,j,l,r四个指针,注意去重和剪枝(非必须)。
class Solution {
public:
vector<vector<int>> fourSum(vector<int>& nums, int target) {
int n = nums.size();
vector<vector<int>> res;
if (n < ) return res;
sort(nums.begin(), nums.end());
for (int i = ; i < n - ; i++) {
if (i > && nums[i] == nums[i - ]) continue;
if (nums[i] + nums[i + ] + nums[i + ] + nums[i + ] > target) break;
if (nums[i] + nums[n - ] + nums[n - ] + nums[n - ] < target) continue;
for (int j = i + ; j < n - ; j++) {
if (j > i + && nums[j] == nums[j - ]) continue;
if (nums[i] + nums[j] + nums[j + ] + nums[j + ] > target) break;
if (nums[i] + nums[j] + nums[n - ] + nums[n - ] < target) continue;
int l = j + , r = n - ;
while (l < r) {
int sum = nums[i] + nums[j] + nums[l] + nums[r];
if (sum < target) l++;
else if (sum > target) r--;
else {
res.push_back({nums[i], nums[j], nums[l], nums[r]});
for (l++; l < r && nums[l] == nums[l - ]; l++);
for (r--; l < r && nums[r] == nums[r + ]; r--);
}
}
}
}
return res;
}
};
38. Count and Say
https://leetcode.com/problems/count-and-say/description/
双指针,将序列模仿出来即可。
class Solution {
public:
string countAndSay(int n) {
if (n < ) return "";
string s = "";
while (--n) {
int b = , e = , l = s.size();
string res = "";
while (b < l) {
while (e < l && s[b] == s[e]) e++;
res += to_string(e - b);
res += s[b];
b = e;
}
s = res;
}
return s;
}
};
16. 3Sum Closest
https://leetcode.com/problems/3sum-closest/?tab=Description
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. For example, given array S = {- -}, and target = . The sum that is closest to the target is . (- + + = ).
desc
和18题非常相近,而且要简单很多。仿照18题的思路写了大部分,结果最后一行更新left和right的时候走入弯道了,看了讨论区的算法有了想法。变量名写错,三目运算符写错,一刷没能AC。
class Solution {
public:
int threeSumClosest(vector<int>& nums, int target) {
sort(nums.begin(), nums.end());
int n = nums.size(), res = ;
if (n <= ) {
for (auto n: nums) {
res += n;
}
return res;
}
if (nums[] + nums[] + nums[] >= target) {
return nums[] + nums[] + nums[];
}
if (nums[n - ] + nums[n - ] + nums[n - ] <= target) {
return nums[n - ] + nums[n - ] + nums[n - ];
}
res = nums[] + nums[] + nums[];
for (int i = ; i < n - ; i++) {
if (i > && nums[i] == nums[i - ]) {
continue;
}
int left = i + , right = n - ;
while (left < right) {
int sum = nums[i] + nums[left] + nums[right];
abs(res - target) < abs(sum - target) ? res : res = sum;
if (res == target) {
return res;
}
sum < target ? left++ : right--;
}
}
return res;
}
};
15. 3Sum
https://leetcode.com/problems/3sum/?tab=Description
Given an array S of n integers, are there elements a, b, c in S such that a + b + c = ? Find all unique triplets in the array which gives the sum of zero. Note: The solution set must not contain duplicate triplets. For example, given array S = [-, , , , -, -], A solution set is:
[
[-, , ],
[-, -, ]
]
desc
15,16,18思路一样,但是都没有一次AC。一种算法,在不理解的情况下,至少要写5次才能懂得每一步的精髓!一刷去重条件写错,没能AC。二刷一次AC。
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
int n = nums.size();
vector<vector<int>> res;
if (n < ) {
return res;
}
sort(nums.begin(), nums.end());
for (int i = ; i < n - ; i++) {
if (i > && nums[i] == nums[i - ]) {
continue;
}
if (nums[i] + nums[i + ] + nums[i + ] > ) {
break;
}
if (nums[i] + nums[n - ] + nums[n - ] < ) {
continue;
}
int l = i + , r = n - ;
while (l < r) {
int sum = nums[i] + nums[l] + nums[r];
if (sum < ) {
l++;
} else if (sum > ) {
r--;
} else {
res.push_back({nums[i], nums[l], nums[r]});
do {
l++;
} while (l < r && nums[l] == nums[l - ]);
do {
r--;
} while (l < r && nums[r] == nums[r + ]);
}
}
}
return res;
}
};
11. Container With Most Water
https://leetcode.com/problems/container-with-most-water/?tab=Description
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, ). 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 .
desc
双指针。左右指针分别从数组两端开始,两指针夹逼过程中,矩形的长变小,只有宽增大,面积才会增大。
class Solution {
public:
int maxArea(vector<int>& height) {
int i = , j = height.size() - ;
int water = ;
while (i < j) {
int h = min(height[i], height[j]);
water = max(water, h * (j - i));
while (i < j && height[i] <= h) {
i++;
}
while (i < j && height[j] <= h) {
j--;
}
}
return water;
}
};
535. Encode and Decode TinyURL
https://leetcode.com/problems/encode-and-decode-tinyurl/#/description
TinyURL is a URL shortening service where you enter a URL such as https://leetcode.com/problems/design-tinyurl and it returns a short URL such as http://tinyurl.com/4e9iAk. Design the encode and decode methods for the TinyURL service. There is no restriction on how your encode/decode algorithm should work. You just need to ensure that a URL can be encoded to a tiny URL and the tiny URL can be decoded to the original URL.
desc
比较简单的一道题,但是就是没思路,好烦,可能我做的题还是不够多吧……,很多C++的STL操作都忘掉了,上周写了不少python之后,现在写C++老是忘记写;在不同的语言之间来回切换容易精神错乱!一刷没AC。
class Solution {
private:
unordered_map<string, string> url2code;
unordered_map<string, string> code2url;
string alphabet; void changeAlphabet(char begin, char end) {
for (char c = begin; c <= end; c++) {
alphabet.push_back(c);
}
}
public:
// Encodes a URL to a shortened URL.
string encode(string longUrl) {
if (alphabet == "") {
changeAlphabet('', '');
changeAlphabet('A', 'Z');
changeAlphabet('a', 'z');
}
string code = "";
while (url2code.find(longUrl) == url2code.end()) {
code = "";
srand((unsigned)time(NULL));
for (int i = ; i < ; i++) {
int idx = rand() % (alphabet.size());
code.push_back(alphabet[idx]);
}
if (code2url.find(code) == code2url.end()) {
code2url[code] = longUrl;
url2code[longUrl] = code;
}
}
return string("http://tinyurl.com/") += code;
} // Decodes a shortened URL to its original URL.
string decode(string shortUrl) {
string code = shortUrl.substr(shortUrl.size() - , );
return code2url[code];
}
}; // Your Solution object will be instantiated and called as such:
// Solution solution;
// solution.decode(solution.encode(url));
508. Most Frequent Subtree Sum
https://leetcode.com/problems/most-frequent-subtree-sum/#/description
Given the root of a tree, you are asked to find the most frequent subtree sum. The subtree sum of a node is defined as the sum of all the node values formed by the subtree rooted at that node (including the node itself). So what is the most frequent subtree sum value? If there is a tie, return all the values with the highest frequency in any order.
desc
不算难,现在衡量难与不难的标准是看了有没有思路。有思路但是花很长时间肉眼debug才A掉这个题。而且思路没有简化到极致。最大的那个count可以在遍历树的过程中找到,我是遍历完树之后再遍历map找的,map中的元素可以自动初始化,这种情况和python不一样,不用判断键是否存在!经过优化之后,代码非常简洁而且效率提高了一倍。一刷没有AC。二刷没有一次AC,注意iterator的操作不能使用<,只能使用!=和=。
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
vector<int> findFrequentTreeSum(TreeNode* root) {
vector<int> res;
if(root == NULL) {
return res;
}
unordered_map<int, int> m;
helper(root, m);
// 查看map中count最大的
int maxCount = m.begin()->second;
for(auto i = m.begin(); i != m.end(); i++) {
i->second > maxCount ? maxCount = i->second : maxCount;
}
for(auto i = m.begin(); i != m.end(); i++) {
if ((i->second) == maxCount) {
res.push_back(i->first);
}
}
return res;
}
int helper(TreeNode* r, unordered_map<int, int>& m) {
int sum = r->val;
if(r->left && !r->right) {
sum += helper(r->left, m);
} else if(!r->left && r->right) {
sum += helper(r->right, m);
} else if(r->left && r->right) {
sum += helper(r->left, m);
sum += helper(r->right, m);
} else
{}
if(m.find(sum) == m.end()) {
m[sum] = ;
} else {
m[sum]++;
}
return sum;
}
};
raw Code
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
vector<int> findFrequentTreeSum(TreeNode* root) {
vector<int> res;
unordered_map<int, int> m;
int maxCount = ;
helper(root, m, maxCount);
for(auto i = m.begin(); i != m.end(); i++) {
if ((i->second) == maxCount) {
res.push_back(i->first);
}
}
return res;
}
int helper(TreeNode* r, unordered_map<int, int>& m, int& maxCount) {
if (!r) {
return ;
}
int sum = r->val;
sum += helper(r->left, m, maxCount);
sum += helper(r->right, m, maxCount);
m[sum]++;
maxCount = max(maxCount, m[sum]);
return sum;
}
};
Modified Code
1. Two Sum
https://leetcode.com/problems/two-sum/description/
multimap存储去掉一个数之和的target,遍历数组查找是否有数字。
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
unordered_multimap<int, int> m;
vector<int> res(, );
for (int i = ; i < nums.size(); i++) m.insert({target - nums[i], i});
for (int i = ; i < nums.size(); i++) {
auto p = m.equal_range(nums[i]);
for (auto iter = p.first; iter != p.second; iter++) {
if (iter->second != i) {
res[] = iter->second;
res[] = i;
return res;
}
}
}
return res;
}
};
500. Keyboard Row
https://leetcode.com/problems/keyboard-row/#/description
Given a List of words, return the words that can be typed using letters of alphabet on only one row's of American keyboard like the image below.
desc
现在连easy级的题都没法一刷AC了,真是菜啊!再刷!!二刷一次AC!
class Solution {
public:
vector<string> findWords(vector<string>& words) {
string s1("qwertyuiop");
string s2("asdfghjkl");
string s3("zxcvbnm");
unordered_set<char> m1(s1.begin(), s1.end());
unordered_set<char> m2(s2.begin(), s2.end());
unordered_set<char> m3(s3.begin(), s3.end());
vector<string> res;
for (auto w: words) {
if(w.size() == ) {
res.push_back(w);
}
unordered_set<char> temp;
char ch;
if (w[] <= 'Z' && w[] >= 'A') {
ch = w[] + ;
} else {
ch = w[];
}
if (m1.find(ch) != m1.end()) {
temp = m1;
} else if (m2.find(ch) != m2.end()) {
temp = m2;
} else if (m3.find(ch) != m3.end()) {
temp = m3;
} else {
continue;
}
bool flag = true;
for (auto c: w) {
if (c <= 'Z' && c >= 'A') {
ch = c + ;
} else {
ch = c;
}
if (temp.find(ch) == temp.end()) {
flag = false;
break;
}
}
if (flag) {
res.push_back(w);
}
}
return res;
}
};
454. 4Sum II
https://leetcode.com/problems/4sum-ii/#/description
Given four lists A, B, C, D of integer values, compute how many tuples (i, j, k, l) there are such that A[i] + B[j] + C[k] + D[l] is zero. To make problem a bit easier, all A, B, C, D have same length of N where ≤ N ≤ . All integers are in the range of - to - and the result is guaranteed to be at most - .
desc
没有思路,要再刷两遍!一刷没AC,res更新不是加1,而是加上map中的count!二刷一次AC,但是思路理解并不流畅!还要再刷!
class Solution {
public:
int fourSumCount(vector<int>& A, vector<int>& B, vector<int>& C, vector<int>& D) {
unordered_map<int, int> sumCount;
for (int i = ; i < A.size(); i++) {
for (int j = ; j < B.size(); j++) {
int sum = A[i] + B[j];
sumCount[sum]++;
}
}
int res = ;
for (int i = ; i < C.size(); i++) {
for (int j = ; j < D.size(); j++) {
int sum = C[i] + D[j];
auto iter = sumCount.find(-sum);
if (iter != sumCount.end()) {
res += iter->second;
}
}
}
return res;
}
};
451. Sort Characters By Frequency
https://leetcode.com/problems/sort-characters-by-frequency/#/description
Given a string, sort it in decreasing order based on the frequency of characters. Example : Input:
"tree" Output:
"eert" Explanation:
'e' appears twice while 'r' and 't' both appear once.
So 'e' must appear before both 'r' and 't'. Therefore "eetr" is also a valid answer.
desc
比较简单,但是比较考基本功,但是还是不明白为啥要用static关键字!!!一刷没AC,注意map使用[]操作查询时,不存在的键会自动生成!而值会调用相应的默认构造函数!这是c++的一大优点。
class Solution {
public:
string frequencySort(string s) {
unordered_map<char, int> alpha2Count;
for (char c: s) {
alpha2Count[c]++;
}
vector<pair<char, int>> vec(alpha2Count.begin(), alpha2Count.end());
sort(vec.begin(), vec.end(), myCompare);
string res;
for (auto i = vec.begin(); i != vec.end(); i++) {
for (int k = ; k < i->second; k++) {
res.push_back(i->first);
}
}
return res;
}
static bool myCompare(pair<char, int>& l, pair<char, int>& r) {
return l.second > r.second;
}
};
438. Find All Anagrams in a String
https://leetcode.com/problems/find-all-anagrams-in-a-string/#/description
Given a string s and a non-empty string p, find all the start indices of p's anagrams in s. Strings consists of lowercase English letters only and the length of both strings s and p will not be larger than ,. The order of output does not matter.
desc
没思路,一刷没AC,注意滑动窗口,这是个等大小的窗口,只是用vector而不是用map的算法效率不高。
class Solution {
public:
vector<int> findAnagrams(string s, string p) {
vector<int> sv(, ), pv(, ), res;
if (s.size() < p.size()) {
return res;
}
for (int i = ; i < p.size(); i++) {
sv[s[i] - 'a']++;
pv[p[i] - 'a']++;
}
if (sv == pv) {
res.push_back();
}
for (int i = p.size(); i < s.size(); i++) {
sv[s[i] - 'a']++;
sv[s[i - p.size()] - 'a']--;
if (sv == pv) {
res.push_back(i - p.size() + );
}
}
return res;
}
};
380. Insert Delete GetRandom O(1)
https://leetcode.com/problems/insert-delete-getrandom-o1/#/description
class RandomizedSet {
private:
unordered_map<int, int> val2Idx;
vector<int> vals;
public:
/** Initialize your data structure here. */
RandomizedSet() {
vals.push_back();
} /** Inserts a value to the set. Returns true if the set did not already contain the specified element. */
bool insert(int val) {
if (val2Idx.find(val) == val2Idx.end()) {
vals.push_back(val);
vals[]++;
val2Idx[val] = vals[];
return true;
} else {
if (val2Idx[val] < ) {
val2Idx[val] = -val2Idx[val];
vals[]++;
return true;
}
}
return false;
} /** Removes a value from the set. Returns true if the set contained the specified element. */
bool remove(int val) {
if (val2Idx.find(val) != val2Idx.end() && val2Idx[val] > ) {
val2Idx[val] = -val2Idx[val];
vals[]--;
return true;
} else {
return false;
}
} /** Get a random element from the set. */
int getRandom() {
int i = rand() % vals.size();
while (val2Idx[vals[i]] < || i == ) {
i = rand() % vals.size();
}
return vals[i];
}
}; /**
* Your RandomizedSet object will be instantiated and called as such:
* RandomizedSet obj = new RandomizedSet();
* bool param_1 = obj.insert(val);
* bool param_2 = obj.remove(val);
* int param_3 = obj.getRandom();
*/
desc
一刷没AC,注意get_random的时候index不能为0!
274. H-Index
https://leetcode.com/problems/h-index/#/description
Given an array of citations (each citation is a non-negative integer) of a researcher, write a function to compute the researcher's h-index. According to the definition of h-index on Wikipedia: "A scientist has index h if h of his/her N papers have at least h citations each, and the other N − h papers have no more than h citations each." For example, given citations = [, , , , ], which means the researcher has papers in total and each of them had received , , , , citations respectively. Since the researcher has papers with at least citations each and the remaining two with no more than citations each, his h-index is . Note: If there are several possible values for h, the maximum one is taken as the h-index.
desc
一刷没思路!注意vector和Hashmap的查找复杂度都是O(1)!开数组,多加一个元素用于存储引用数大于size的个数。
class Solution {
public:
int hIndex(vector<int>& citations) {
int c_size = citations.size();
vector<int> count(c_size + , );
for (int i = ; i < c_size; i++) {
if (citations[i] >= c_size) {
count[c_size]++;
} else {
count[citations[i]]++;
}
}
int res = ;
for (int i = c_size; i >= ; i--) {
res += count[i];
if (res >= i) {
return i;
}
}
return ;
}
};
166. Fraction to Recurring Decimal
https://leetcode.com/problems/fraction-to-recurring-decimal/#/description
Given two integers representing the numerator and denominator of a fraction, return the fraction in string format. If the fractional part is repeating, enclose the repeating part in parentheses. For example, Given numerator = , denominator = , return "0.5".
Given numerator = , denominator = , return "".
Given numerator = , denominator = , return "0.(6)".
Hint: No scary math, just apply elementary math knowledge. Still remember how to perform a long division?
desc
一刷没AC,磕磕碰碰,花了很长时间,但是最后肉眼debug成功了。再刷! 注意极端情况如0,如负数,还有超出界限的问题。效率不高。
class Solution {
public:
string fractionToDecimal(int numerator, int denominator) {
unordered_map<int, int> div2Pos;
string s;
long long num = numerator;
long long div = denominator;
if (num * div < ) {
s += "-";
}
num = abs(num);
div = abs(div);
s += to_string(num / div);
num %= div;
if (num == ) {
return s;
}
s += ".";
int pos = ;
bool flag = false;
while (num) {
num *= ;
if (div2Pos.find(num) != div2Pos.end()) {
s += ")";
flag = true;
break;
} else {
div2Pos[num] = pos;
s += to_string(num / div);
}
pos++;
num %= div;
cout << num << endl;
} if (flag) {
int p = s.find(".");
s.insert(p + div2Pos[num], "(");
}
return s;
}
};
// upgraded parameter types
string fractionToDecimal(int64_t n, int64_t d) {
// zero numerator
if (n == ) return ""; string res;
// determine the sign
if (n < ^ d < ) res += '-'; // remove sign of operands
n = abs(n), d = abs(d); // append integral part
res += to_string(n / d); // in case no fractional part
if (n % d == ) return res; res += '.'; unordered_map<int, int> map; // simulate the division process
for (int64_t r = n % d; r; r %= d) {
// meet a known remainder
// so we reach the end of the repeating part
if (map.count(r) > ) {
res.insert(map[r], , '(');
res += ')';
break;
} // the remainder is first seen
// remember the current position for it
map[r] = res.size(); r *= ; // append the quotient digit
res += to_string(r / d);
} return res;
}
clear
138. Copy List with Random Pointer
https://leetcode.com/problems/copy-list-with-random-pointer/#/description
A linked list is given such that each node contains an additional random pointer which could point to any node in the list or null. Return a deep copy of the list.
desc
HashMap。使用hashmap记录就链表节点到新链表节点的对照,然后按单链表的顺序复制即可。
/**
* Definition for singly-linked list with a random pointer.
* struct RandomListNode {
* int label;
* RandomListNode *next, *random;
* RandomListNode(int x) : label(x), next(NULL), random(NULL) {}
* };
*/
class Solution {
public:
RandomListNode *copyRandomList(RandomListNode *head) {
if (!head) return head;
RandomListNode *new_head = new RandomListNode(head->label), *tmp = new_head;
unordered_map<RandomListNode*, RandomListNode*> visit;
visit[head] = new_head;
while (head) {
if (head->next) {
if (visit.find(head->next) == visit.end()) {
tmp->next = new RandomListNode(head->next->label);
visit[head->next] = tmp->next;
} else tmp->next = visit[head->next];
}
if (head->random) {
if (visit.find(head->random) == visit.end()) {
tmp->random = new RandomListNode(head->random->label);
visit[head->random] = tmp->random;
} else tmp->random = visit[head->random];
}
head = head->next; tmp = tmp->next;
}
return new_head;
}
};
133. Clone Graph
https://leetcode.com/problems/clone-graph/description/
graph的dfs, 注意图中可能有环,同138非常相似。
94. Binary Tree Inorder Traversal
https://leetcode.com/problems/binary-tree-inorder-traversal/#/description
Given a binary tree, return the inorder traversal of its nodes' values. For example:
Given binary tree [,null,,], \ / return [,,]. Note: Recursive solution is trivial, could you do it iteratively?
desc
二叉树的前、中、后遍历的递归和非递归算法都要很熟悉。
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
vector<int> inorderTraversal(TreeNode* root) {
vector<int> res;
if (!root) return res;
stack<TreeNode*> s; s.push(root);
while (s.top()->left) s.push(s.top()->left);
while (!s.empty()) {
auto cur = s.top(); s.pop(); res.push_back(cur->val);
cur = cur->right;
if (cur) {
s.push(cur);
while (s.top()->left) s.push(s.top()->left);
}
}
return res;
}
};
49. Group Anagrams
https://leetcode.com/problems/anagrams/#/description
Given an array of strings, group anagrams together. For example, given: ["eat", "tea", "tan", "ate", "nat", "bat"],
Return: [
["ate", "eat","tea"],
["nat","tan"],
["bat"]
]
desc
map使用红黑树实现,而unordered_map基于hash table,使用hash型数据结构必须保证key的类型有hash()方法,容器类型除了string外默认是没有hash()方法的,而非hash型数据结构没有限制!c++中对于map和unordered_map,使用[]方法访问当key不存在时调用value的默认构造函数。
class Solution {
public:
vector<vector<string>> groupAnagrams(vector<string>& strs) {
map<vector<int>, vector<string>> m;
for (auto str : strs) {
vector<int> tmp(, );
for (char c : str) tmp[c - 'a']++;
m[tmp].push_back(str);
}
vector<vector<string>> res;
for (auto iter = m.begin(); iter != m.end(); iter++) res.push_back(iter->second);
return res;
}
};
445. Add Two Numbers II
https://leetcode.com/problems/add-two-numbers-ii/#/description
You are given two non-empty linked lists representing two non-negative integers. The most significant digit comes first 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 itself. Follow up:
What if you cannot modify the input lists? In other words, reversing the lists is not allowed.
desc
很简单,但是没有一次AC!而且我的方法时间和空间复杂度都比较高。
/**
* 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 *h1 = NULL;
ListNode *h2 = NULL;
while (l1) {
ListNode *temp = new ListNode(l1->val);
temp->next = h1;
h1 = temp;
l1 = l1->next;
}
while (l2) {
ListNode *temp = new ListNode(l2->val);
temp->next = h2;
h2 = temp;
l2 = l2->next;
}
ListNode *h3 = NULL;
int m = ;
while (h1 || h2 || m) {
int sum = ;
if (h1 && h2) {
sum = h1->val + h2->val + m;
h1 = h1->next;
h2 = h2->next;
} else if (h1) {
sum = h1->val + m;
h1 = h1->next;
} else if (h2) {
sum = h2->val + m;
h2 = h2->next;
} else {
sum = m;
}
ListNode *temp = new ListNode(sum % );
m = sum / ;
temp->next = h3;
h3 = temp;
}
return h3;
}
};
328. Odd Even Linked List
https://leetcode.com/problems/odd-even-linked-list/#/description
Given a singly linked list, group all odd nodes together followed by the even nodes. Please note here we are talking about the node number and not the value in the nodes. You should try to do it in place. The program should run in O() space complexity and O(nodes) time complexity. Example:
Given ->->->->->NULL,
return ->->->->->NULL. Note:
The relative order inside both the even and odd groups should remain as it was in the input.
The first node is considered odd, the second node even and so on ...
desc
很简单的一道题,题意理解错误,正确理解题意后一次AC。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* oddEvenList(ListNode* head) {
ListNode *odd_head = new ListNode();
ListNode *even_head = new ListNode();
ListNode *odd = odd_head;
ListNode *even = even_head;
for (int i = ; head; i++) {
if (i % == ) {
odd->next = head;
odd = odd->next;
} else {
even->next = head;
even = even->next;
}
head = head->next;
}
odd->next = even_head->next;
even->next = NULL;
return odd_head->next;
}
};
148. Sort List
https://leetcode.com/problems/sort-list/#/description
Sort a linked list in O(n log n) time using constant space complexity.
desc
TP。双指针找到中点,递归排序再merge。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* sortList(ListNode* head) {
if (!head || !head->next) return head;
ListNode *prev = NULL, *slow = head, *fast = head;
while (fast && fast->next) {
prev = slow; slow = slow->next; fast = fast->next->next;
}
if (prev) prev->next = NULL;
ListNode *l1 = sortList(head), *l2 = sortList(slow);
return merge(l1, l2);
} ListNode* merge(ListNode* l1, ListNode* l2) {
ListNode *head = new ListNode(), *h = head;
while (l1 && l2) {
if (l1->val < l2->val) {
h->next = l1; l1 = l1->next;
} else {
h->next = l2; l2 = l2->next;
}
h = h->next;
}
if (l2) h->next = l2;
else h->next = l1;
return head->next;
}
};
147. Insertion Sort List Add to List
https://leetcode.com/problems/insertion-sort-list/#/description
Sort a linked list using insertion sort.
desc
指针。使用dummy node作为新的头结点,将原链表的节点依次插入到新链表中。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* insertionSortList(ListNode* head) {
if (!head) return head;
ListNode *h = new ListNode(), *temp, *pre;
while (head) {
pre = h; temp = h->next;
while (temp && temp->val < head->val) {
pre = temp; temp = temp->next;
}
ListNode *head_next = head->next;
pre->next = head;
head->next = temp;
head = head_next;
}
return h->next;
}
};
143. Reorder List
https://leetcode.com/problems/reorder-list/#/description
Given a singly linked list L: L0→L1→…→Ln-→Ln,
reorder it to: L0→Ln→L1→Ln-→L2→Ln-→… You must do this in-place without altering the nodes' values. For example,
Given {,,,}, reorder it to {,,,}.
desc
TP。用快慢指针分离前段和后段链表,将后段倒置,之后将后段链表每个节点逐个插入到前段中
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
void reorderList(ListNode* head) {
if (!head || !head->next || !head->next->next) return; //链表少于两个节点直接返回
ListNode *slow = head, *fast = head, *pre = NULL;
while (fast && fast->next) { // 快慢指针将链表对半分
pre = slow; slow = slow->next; fast = fast->next->next;
}
if (!fast) slow = pre; //节点为偶数,slow向前进一个,将正中间的节点归到左侧
ListNode *right_head = NULL, *cur = slow->next, *left_head = head, *tmp; // cur为当前右侧链表的开头
cout << slow->val << endl;
slow->next = NULL; //将左、右侧链表分离
while(cur) { // 将右侧链表使用头插法倒置
tmp = cur->next; cur->next = right_head; right_head = cur; cur = tmp;
}
while (right_head) { // 将右侧链表逐个插入左侧链表
tmp = right_head->next; right_head->next = left_head->next; left_head->next = right_head; right_head = tmp; left_head = left_head->next->next;
}
}
};
19. Remove Nth Node From End of List
https://leetcode.com/problems/remove-nth-node-from-end-of-list/description/
Given a linked list, remove the nth node from the end of list and return its head. For example, Given linked list: ->->->->, and n = . After removing the second node from the end, the linked list becomes ->->->.
Note:
Given n will always be valid.
Try to do this in one pass.
双指针,先将快指针定位到n + 1处,维持快慢指针的间隔,直到快指针到了fast处,将慢指针后面的节点删除。注意要使用dummy节点作为新的头结点。
/**
* 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* new_head = new ListNode(), *slow = new_head, *fast = new_head;
new_head->next = head;
for (int i = ; i <= n + ; i++) fast = fast->next;
while (fast) {
slow = slow->next;
fast = fast->next;
}
slow->next = slow->next->next;
return new_head->next;
}
};
26. Remove Duplicates from Sorted Array
https://leetcode.com/problems/remove-duplicates-from-sorted-array/description/
双指针。
class Solution {
public:
int removeDuplicates(vector<int>& nums) {
int l = ;
for (int i = , count = ; i < nums.size(); i++) {
if (i == || nums[i] == nums[i - ]) count++;
else count = ;
if (count == ) nums[l++] = nums[i];
}
return l;
}
};
80. Remove Duplicates from Sorted Array II
https://leetcode.com/problems/remove-duplicates-from-sorted-array-ii/
双指针。同26,只是最多保留两个重复元素。遍历数组,更新len。使用count记录重复个数,只有重复个数为1或2时更新len。
class Solution {
public:
int removeDuplicates(vector<int>& nums) {
int len = ;
for (int end = , count = ; end < nums.size(); end++) {
if (end == || nums[end] == nums[end - ]) count++;
else count = ;
if (count == || count == ) nums[len++] = nums[end];
}
return len;
}
};
27. Remove Element
原地操作,删除数组中的固定值的元素。
双指针。
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
int i = , j = ;
while (i < nums.size()) {
if (nums[i] != val) nums[j++] = nums[i];
i++;
}
return j;
}
};
142. Linked List Cycle II
https://leetcode.com/problems/linked-list-cycle-ii/#/description
Given a linked list, return the node where the cycle begins. If there is no cycle, return null. Note: Do not modify the linked list.
desc
一刷由于判断语句中“==”写成了“=”没能AC,链表成环还有不清楚的地方,就是为什么相遇时slow不可能完整遍历链表了??注意使用新起的节点作为起始点,避免head指向head的情况。二刷没有一次AC,添加新的头结点忘记和原链表连上了,精简了代码。三刷第一步判断head之后返回写错,应该直接返回NULL,没有AC。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
if (!head || !head->next) {
return NULL;
}
ListNode *newHead = new ListNode();
newHead->next = head;
ListNode *slow = newHead, *fast = newHead;
while (fast && fast->next) {
if (slow != newHead && slow == fast) {
break;
}
slow = slow->next;
fast = fast->next->next;
}
if (!fast || !fast->next) {
return NULL;
} else {
fast = newHead;
while (fast != slow) {
fast = fast->next;
slow = slow->next;
}
return slow;
}
}
};
206. Reverse Linked List
链表反转
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* reverseList(ListNode* head) {
ListNode* new_head = NULL;
while (head) {
auto next = head->next;
head->next = new_head;
new_head = head;
head = next;
}
return new_head;
}
};
92. Reverse Linked List II
https://leetcode.com/problems/reverse-linked-list-ii/#/description
Reverse a linked list from position m to n. Do it in-place and in one-pass. For example:
Given ->->->->->NULL, m = and n = , return ->->->->->NULL. Note:
Given m, n satisfy the following condition:
≤ m ≤ n ≤ length of list.
desc
双指针,头插法。分别用pre和end记录要翻转的部分的前一个节点和后一个节点,然后使用头插法即可。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* reverseBetween(ListNode* head, int m, int n) {
ListNode *new_head = new ListNode(), *pre = new_head, *end = new_head;
new_head->next = head;
for (int i = ; i <= n; i++) {
if (i < m - ) pre = pre->next;
end = end->next;
}
auto tmp = pre->next; pre->next = end;
while (tmp != end) {
auto next = tmp->next;
tmp->next = pre->next;
pre->next = tmp;
tmp = next;
}
return new_head->next;
}
};
61. Rotate List
https://leetcode.com/problems/rotate-list/#/description
Given a list, rotate the list to the right by k places, where k is non-negative. For example:
Given ->->->->->NULL and k = ,
return ->->->->->NULL.
desc
双指针。注意要首先得出链表长度len,再将旋转次数对len取模,避免多余计算和可能的错误。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* rotateRight(ListNode* head, int k) {
if (!head) return head;
int len = ;
for (auto tmp = head; tmp; tmp = tmp->next, len++);
k %= len;
ListNode *new_head = new ListNode(), *fast = new_head, *slow = new_head;
new_head->next = head;
while(k-- && fast) fast = fast->next;
while (fast && fast->next) {
slow = slow->next;
fast = fast->next;
}
fast->next = new_head->next;
auto res = slow->next;
slow->next = NULL;
return res;
}
};
83. Remove Duplicates from Sorted List
https://leetcode.com/problems/remove-duplicates-from-sorted-list/description/
双指针。用pre和cur两个指针,cur走到cur和cur->next不等,pre = cur,pre=cur->next, cur=cur->next。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* deleteDuplicates(ListNode* head) {
if (!head || !head->next) return head;
ListNode *new_head = new ListNode(), *pre = new_head, *cur = head;
new_head->next = head;
while (cur) {
for (; cur && cur->next && cur->val == cur->next->val; cur = cur->next);
pre->next = cur;
pre = pre->next;
cur = cur->next;
}
return new_head->next;
}
};
82. Remove Duplicates from Sorted List II
https://leetcode.com/problems/remove-duplicates-from-sorted-list-ii/#/description
Given a sorted linked list, delete all nodes that have duplicate numbers, leaving only distinct numbers from the original list. For example,
Given ->->->->->->, return ->->.
Given ->->->->, return ->.
desc
双指针。同83,记录cur重复次数次,重复一次pre = cur,重复多次pre ->next = cur->next。最后cur=cur->next。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* deleteDuplicates(ListNode* head) {
if (!head || !head->next) return head;
ListNode* new_head = new ListNode(), *pre = new_head, *cur = head;
new_head->next = head;
while (cur) {
int dup;
for (dup = ; cur && cur->next && cur->val == cur->next->val; dup++) cur = cur->next;
if (dup == ) pre = cur;
else pre->next = cur->next;
cur = cur->next;
}
return new_head->next;
}
};
86. Partition List
https://leetcode.com/problems/partition-list/#/description
Given a linked list and a value x, partition it such that all nodes less than x come before nodes greater than or equal to x. You should preserve the original relative order of the nodes in each of the two partitions. For example,
Given ->->->->-> and x = ,
return ->->->->->.
desc
双指针。设置两个dummy node对于两部分分别进行尾插法,形成两个链表然后接上。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* partition(ListNode* head, int x) {
if (!head || !head->next) return head;
ListNode *head1 = new ListNode(), *head2 = new ListNode(), *tail1 = head1, *tail2 = head2;
while (head) {
auto tmp = head->next;
if (head->val < x) {
tail1->next = head;
tail1 = tail1->next;
} else {
tail2->next = head;
tail2 = tail2->next;
}
head = tmp;
}
tail1->next = head2->next;
tail2->next = NULL;
return head1->next;
}
};
523. Continuous Subarray Sum
https://leetcode.com/problems/continuous-subarray-sum/#/description
Given a list of non-negative numbers and a target integer k, write a function to check if the array has a continuous subarray of size at least that sums up to the multiple of k, that is, sums up to n*k where n is also an integer. Example :
Input: [, , , , ], k=
Output: True
Explanation: Because [, ] is a continuous subarray of size and sums up to .
desc
思路是什么?
class Solution {
public:
bool checkSubarraySum(vector<int>& nums, int k) {
unordered_map<int, int> m;
m[] = -;
int sum = ;
for (int i = ; i < nums.size(); i++) {
sum += nums[i];
if (k != ) {
sum %= k;
}
if (m.find(sum) != m.end()) {
int pre = (m.find(sum))->second;
if (i - pre > ) {
return true;
}
} else {
m[sum] = i;
}
}
return false;
}
};
462. Minimum Moves to Equal Array Elements II
https://leetcode.com/problems/minimum-moves-to-equal-array-elements-ii/#/description
Given a non-empty integer array, find the minimum number of moves required to make all array elements equal, where a move is incrementing a selected element by or decrementing a selected element by . You may assume the array's length is at most 10,000. Example: Input:
[,,] Output: Explanation:
Only two moves are needed (remember each move increments or decrements one element): [,,] => [,,] => [,,]
desc
这个问题中数列的平衡杆不一定就是均值,因为经过排序后两端每对数字移动的总距离和均值无关。当数字有偶数个时,以均值直接算作平衡杆正确;当数字有奇数个且中间那个数恰好为均值时,用均值作为平衡杆也正确;但是当中间那个数不是均值时,就应该用中间那个数作为平衡杆,亦即中间那个数不需要移动!
一次AC,但是思路不是自己的,还要再刷!我开始的思路就是直接算均值,思路有漏洞,应该想到排序的!
class Solution {
public:
int minMoves2(vector<int>& nums) {
sort(nums.begin(), nums.end());
int i = , j = nums.size() - ;
int res = ;
while (i < j) {
res += nums[j] - nums[i];
i++;
j--;
}
return res;
}
};
441. Arranging Coins
https://leetcode.com/problems/arranging-coins/#/description
You have a total of n coins that you want to form in a staircase shape, where every k-th row must have exactly k coins. Given n, find the total number of full staircase rows that can be formed. n is a non-negative integer and fits within the range of a -bit signed integer. Example : n = The coins can form the following rows:
¤
¤ ¤
¤ ¤ Because the 3rd row is incomplete, we return .
Example : n = The coins can form the following rows:
¤
¤ ¤
¤ ¤ ¤
¤ ¤ Because the 4th row is incomplete, we return .
desc
很简单的数学问题,就是个一元二次方程求解的问题,我忘记用公式了。用了个O(long N)的方法,用公式一次一次开方就OK了。一次AC。
class Solution {
public:
int arrangeCoins(int n) {
return int((- + sqrt( + * long(n)) ) / );
}
};
423. Reconstruct Original Digits from English
https://leetcode.com/problems/reconstruct-original-digits-from-english/#/description
Given a non-empty string containing an out-of-order English representation of digits -, output the digits in ascending order. Note:
Input contains only lowercase English letters.
Input is guaranteed to be valid and can be transformed to its original digits. That means invalid inputs such as "abc" or "zerone" are not permitted.
Input length is less than ,.
Example :
Input: "owoztneoer" Output: ""
Example :
Input: "fviefuro" Output: ""
desc
比较简单的多元方程组的问题,一刷没AC,因为string和int的互换方法不清CE了,算法效率也不是很高。
class Solution {
private:
string str = "guwxfhsio"; public: string originalDigits(string s) {
unordered_map<char, int> m;
for (char c: str) {
m[c] = ;
}
for (char c: s) {
m[c]++;
}
vector<int> res(, );
res[] = m['g'];
res[] = m['u'];
res[] = m['w'];
res[] = m['x'];
res[] = m['z'];
res[] = m['f'] - res[];
res[] = m['h'] - res[];
res[] = m['s'] - res[];
res[] = m['i'] - res[] - res[] - res[];
res[] = m['o'] - res[] - res[] - res[];
string resStr;
for (int i = ; i < ; i++) {
if (res[i] > ) {
string temp(res[i], char(i + ''));
resStr += temp;
}
}
return resStr;
}
};
415. Add Strings
https://leetcode.com/problems/add-strings/#/description
Given two non-negative integers num1 and num2 represented as string, return the sum of num1 and num2. Note: The length of both num1 and num2 is < .
Both num1 and num2 contains only digits -.
Both num1 and num2 does not contain any leading zero.
You must not use any built-in BigInteger library or convert the inputs to integer directly.
desc
很简单,看了就有思路,一次AC。算法效率好像不太行。
class Solution {
public:
string addStrings(string num1, string num2) {
string res;
int i = , j = , c = ;
int s1 = num1.size(), s2 = num2.size();
for (;i < num1.size() && j < num2.size(); i++, j++) {
int sum = num1[s1 - - i] - '' + num2[s2 - - j] - '' + c;
res = to_string(sum % ) + res;
c = sum / ;
}
if (i < num1.size()) {
for (; i < num1.size(); i++) {
int sum = num1[s1 - - i] - '' + c;
res = to_string(sum % ) + res;
c = sum / ;
} } if (j < num2.size()) {
for (; j < num2.size(); j++) {
int sum = num2[s2 - - j] - '' + c;
res = to_string(sum % ) + res;
c = sum / ;
}
}
if (c) {
res = to_string(c) + res;
}
return res;
}
};
400. Nth Digit
https://leetcode.com/problems/nth-digit/#/description
Find the nth digit of the infinite integer sequence , , , , , , , , , , , ... Note:
n is positive and will fit within the range of a -bit signed integer (n < ). Example : Input: Output: Example : Input: Output: Explanation:
The 11th digit of the sequence , , , , , , , , , , , ... is a , which is part of the number .
desc
思路不是自己的。一刷没AC,因为base设为int类型越界导致WA。再刷!
class Solution {
public:
int findNthDigit(int n) {
long base = , digits = ;
while (n - base * digits > ) {
n -= base * digits;
base *= ;
digits++;
}
int index = n % digits;
// index is the Nth digit in the target num.
if (index == ) {
index = digits;
}
int num = ;
// num is the target num.
for (int i = ; i < digits; i++) {
num *= ;
}
num += (index == digits) ? n / digits - : n / digits;
for (int i = index; i < digits; i++) {
num /= ;
}
return num % ;
}
};
413. Arithmetic Slices
https://leetcode.com/problems/arithmetic-slices/#/description
A sequence of number is called arithmetic if it consists of at least three elements and if the difference between any two consecutive elements is the same. For example, these are arithmetic sequence: , , , ,
, , ,
, -, -, -
The following sequence is not arithmetic. , , , , A zero-indexed array A consisting of N numbers is given. A slice of that array is any pair of integers (P, Q) such that <= P < Q < N. A slice (P, Q) of array A is called arithmetic if the sequence:
A[P], A[p + ], ..., A[Q - ], A[Q] is arithmetic. In particular, this means that P + < Q. The function should return the number of arithmetic slices in the array A. Example: A = [, , , ] return: , for arithmetic slices in A: [, , ], [, , ] and [, , , ] itself.
desc
比较简单,一刷没有AC,不用设置两个begin和end两个变量,只需一个middle就可以了,注意middle从1到A.size() - 2,因为这个WA。因为==写成=CE。
class Solution {
public:
int numberOfArithmeticSlices(vector<int>& A) {
if (A.size() < ) {
return ;
}
int m = , res = ;
while (m < A.size() - ) {
int b = m;
while (A[m] * == A[m - ] + A[m + ] && m < A.size() - ) {
m++;
}
if (m - b > ) {
res += (m - b) * (m - b + ) / ;
} else {
m++;
}
}
return res;
}
};
372. Super Pow
https://leetcode.com/problems/super-pow/#/description
Your task is to calculate ab mod where a is a positive integer and b is an extremely large positive integer given in the form of an array. Example1: a =
b = [] Result:
Example2: a =
b = [,] Result:
desc
思路不是自己的,一刷AC,还要再刷!递归设计的很好!
class Solution {
private:
const int base = ;
int powmod(int a, int k) {
a %= base;
int res = ;
for (int i = ; i < k; i++) {
res = res * a % base;
}
return res;
}
public:
int superPow(int a, vector<int>& b) {
if (b.size() < ) {
return ;
}
int digit = b.back();
b.pop_back();
return powmod(superPow(a, b) , ) * powmod(a, digit) % base;
}
};
368. Largest Divisible Subset
https://leetcode.com/problems/largest-divisible-subset/#/description
Given a set of distinct positive integers, find the largest subset such that every pair (Si, Sj) of elements in this subset satisfies: Si % Sj = or Sj % Si = . If there are multiple solutions, return any subset is fine. Example : nums: [,,] Result: [,] (of course, [,] will also be ok)
Example : nums: [,,,] Result: [,,,]
desc
思路不好,有漏洞,看了讨论区的C++算法,一刷没AC。因为开始没对数组没排序得了WA。再刷!!
class Solution {
public:
vector<int> largestDivisibleSubset(vector<int>& nums) {
sort(nums.begin(), nums.end());
vector<int> counters(nums.size(), );
vector<int> parent(nums.size(), );
int m = , mi = ;
for (int i = nums.size() - ; i >= ; i--) {
for (int j = i; j < nums.size(); j++) {
if (nums[j] % nums[i] == && counters[i] < counters[j] + ) {
counters[i] = counters[j] + ;
parent[i] = j;
if (m < counters[i]) {
m = counters[i];
mi = i;
}
}
}
}
vector<int> res;
for (int i = ; i < m; i++) {
res.push_back(nums[mi]);
mi = parent[mi];
}
return res;
}
};
367. Valid Perfect Square
https://leetcode.com/problems/valid-perfect-square/#/description
Given a positive integer num, write a function which returns True if num is a perfect square else False. Note: Do not use any built-in library function such as sqrt. Example : Input:
Returns: True
Example : Input:
Returns: False
desc
一道简单的二分查找,一刷没有AC。注意一个公式1 + 3 + 5 + 7 + 9 + …… = n^2!因为mid设为int,结果溢出得了WA。
class Solution {
public:
bool isPerfectSquare(int num) {
int low = , high = num;
while (low < high) {
long long mid = low + (high - low) / ;
if (mid * mid < num) {
low = mid + ;
} else {
high = mid;
}
}
return (low * low == num);
}
};
365. Water and Jug Problem
https://leetcode.com/problems/water-and-jug-problem/#/description
You are given two jugs with capacities x and y litres. There is an infinite amount of water supply available. You need to determine whether it is possible to measure exactly z litres using these two jugs. If z liters of water is measurable, you must have z liters of water contained within one or both buckets by the end. Operations allowed: Fill any of the jugs completely with water.
Empty any of the jugs.
Pour water from one jug into another till the other jug is completely full or the first jug itself is empty.
Example : (From the famous "Die Hard" example) Input: x = , y = , z =
Output: True
Example : Input: x = , y = , z =
Output: False
desc
巨硬笔试题,数论问题,挺难的!证明还挺复杂……。最大公约数GCD和最小公倍数LCM还不太会弄!一刷一次AC。但是思路理解起来还是挺费劲的!再刷!
class Solution {
private:
int gcd(int a, int b) {
while (b != ) {
int temp = b;
b = a % b;
a = temp;
}
return a;
}
public:
bool canMeasureWater(int x, int y, int z) {
if (z == ) {
return true;
}
if (x + y < z) {
return false;
}
return z % gcd(x, y) == ;
}
};
343. Integer Break
https://leetcode.com/problems/integer-break/#/description
Given a positive integer n, break it into the sum of at least two positive integers and maximize the product of those integers. Return the maximum product you can get. For example, given n = , return ( = + ); given n = , return ( = + + ). Note: You may assume that n is not less than and not larger than .
desc
一道规律题,一刷没有AC,以为大于号写成小于号得了WA,需要用导数来推导,果然是数学题!
class Solution {
public:
int integerBreak(int n) {
if (n == ) {
return ;
}
if (n == ) {
return ;
}
int res = ;
while (n > ) {
res *= ;
n -= ;
}
res *= n;
return res;
}
};
319. Bulb Switcher
https://leetcode.com/problems/bulb-switcher/#/description
There are n bulbs that are initially off. You first turn on all the bulbs. Then, you turn off every second bulb. On the third round, you toggle every third bulb (turning on if it's off or turning off if it's on). For the ith round, you toggle every i bulb. For the nth round, you only toggle the last bulb. Find how many bulbs are on after n rounds. Example: Given n = . At first, the three bulbs are [off, off, off].
After first round, the three bulbs are [on, on, on].
After second round, the three bulbs are [on, off, on].
After third round, the three bulbs are [on, off, off]. So you should return , because there is only one bulb is on.
desc
规律题,发现了一部分规律,但是没有继续深入,发现的规律还比较浅层。一刷一次AC。
class Solution {
public:
int bulbSwitch(int n) {
return sqrt(n);
}
};
69. Sqrt(x)
https://leetcode.com/problems/sqrtx/#/description
Implement int sqrt(int x). Compute and return the square root of x.
desc
二分法注意0和mid * mid == x的情况。经典方法是Newton法。
class Solution {
public:
int mySqrt(int x) {
if (x == ) {
return ;
}
int low = , high = x;
while (low < high) {
int mid = low + (high - low) / ;
long long prod = mid * mid;
if (mid < x / mid) {
low = mid + ;
} else if (mid == x / mid) {
return mid;
} else {
high = mid;
}
}
return low * low == x ? low : low - ;
}
};
binary search
class Solution {
public:
int mySqrt(int x) {
long r = x;
while (r * r > x) {
r = (r + x / r) / ;
}
return r;
}
};
Newton
313. Super Ugly Number
https://leetcode.com/problems/super-ugly-number/#/description
Write a program to find the nth super ugly number. Super ugly numbers are positive numbers whose all prime factors are in the given prime list primes of size k. For example, [, , , , , , , , , , , ] is the sequence of the first super ugly numbers given primes = [, , , ] of size . Note:
() is a super ugly number for any given primes.
() The given numbers in primes are in ascending order.
() < k ≤ , < n ≤ , < primes[i] < .
() The nth super ugly number is guaranteed to fit in a -bit signed integer.
desc
比较复杂,我有个思路,但是没有想到怎么实现。看了讨论区算法才搞明白,思路不是自己的,一次AC,还要再刷!
class Solution {
public:
int nthSuperUglyNumber(int n, vector<int>& primes) {
vector<int> ugly(n, );
vector<int> val(primes.size(), );
vector<int> idx(primes.size(), ); int next = ;
for (int i = ; i < n; i++) {
ugly[i] = next;
next = INT_MAX;
for (int j = ; j < primes.size(); j++) {
if (val[j] == ugly[i]) {
val[j] = ugly[idx[j]++] * primes[j];
}
next = min(next, val[j]);
}
}
return ugly.back();
}
};
279. Perfect Squares
https://leetcode.com/problems/perfect-squares/#/description
Given a positive integer n, find the least number of perfect square numbers (for example, , , , , ...) which sum to n. For example, given n = , return because = + + ; given n = , return because = + .
desc
没思路,讨论区使用的是DP算法,还有一种数学算法,不太懂,放弃了!一刷没有AC,变量没有定义拿了CE!再刷!
class Solution {
public:
int numSquares(int n) {
if (n <= ) {
return ;
}
vector<int> res{};
res.reserve(n+);
while (res.size() <= n) {
int m = res.size();
int count = INT_MAX;
for (int i = ; i * i <= m; i++) {
count = min(count, res[m - i * i] + );
}
res.push_back(count);
}
return res[n];
}
};
264. Ugly Number II
https://leetcode.com/problems/ugly-number-ii/#/description
Write a program to find the n-th ugly number. Ugly numbers are positive numbers whose prime factors only include , , . For example, , , , , , , , , , is the sequence of the first ugly numbers. Note that is typically treated as an ugly number, and n does not exceed .
desc
和313题很像,我也是用的313题的方法,效率还不错,一刷AC。
class Solution {
public:
int nthUglyNumber(int n) {
vector<int> res(n, );
vector<int> index(, );
vector<int> elem = {, , };
vector<int> val(, );
for (int i = ; i < n; i++) {
int next = INT_MAX;
for (int j = ; j < ; j++) {
if (res[i-] >= val[j]) {
val[j] = res[index[j]++] * elem[j];
}
next = min(next, val[j]);
}
res[i] = next;
}
return res.back();
}
};
50. Pow(x, n)
https://leetcode.com/problems/powx-n/#/description
Implement pow(x, n).
使用进制计算,计算n的2进制表示下的每一位的权值并相乘。注意将n由负转为正时,需要使用long long类型。
class Solution {
public:
double myPow(double x, int n) {
if (n == ) {
return ;
} else {
long b = n;
if (n < ) {
b = -b;
x = / x;
}
return b % == ? myPow(x * x, b / ) : x * myPow(x * x, b / );
}
}
};
recursive
class Solution {
public:
double myPow(double x, int n) {
if (n == ) return ;
if (x < 1e- && x > -1e-) return ;
long long b = n;
if (n < ) {
b = -b;
x = / x;
}
double res = ;
while (b) {
if (b & ) res *= x;
x *= x;
b >>= ;
}
return res;
}
};
iteration
60. Permutation Sequence
https://leetcode.com/problems/permutation-sequence/#/description
The set [,,,…,n] contains a total of n! unique permutations. By listing and labeling all of the permutations in order,
We get the following sequence (ie, for n = ): ""
""
""
""
""
""
Given n and k, return the kth permutation sequence.
desc
题目不简单,看别人的代码很难,对思路还不是很清晰,再刷!
class Solution {
public:
string getPermutation(int n, int k) {
vector<int> num;
for (int i = ; i < n; i++) {
num.push_back(i + );
}
list<int> fact;
fact.push_back();
for (int i = ; i < n; i++) {
fact.push_back(i * fact.back());
}
string res;
k--;
for(int i = n; i > ; i--) {
int ind = k / fact.back();
k %= fact.back();
fact.pop_back();
res += to_string(num[ind]);
num.erase(num.begin() + ind);
}
return res;
}
};
43. Multiply Strings
https://leetcode.com/problems/multiply-strings/#/description
Given two non-negative integers num1 and num2 represented as strings, return the product of num1 and num2. Note: The length of both num1 and num2 is < .
Both num1 and num2 contains only digits -.
Both num1 and num2 does not contain any leading zero.
You must not use any built-in BigInteger library or convert the inputs to integer directly.
desc
大数乘法。从低位到高位,对于结果的每一位都跑一次循环,得到该位的数字并设置全局变量记录进位。初始化结果全零,之后再将高位的0抹去,当结果为0要补个0。
class Solution {
public:
string multiply(string num1, string num2) {
int s1 = num1.size(), s2 = num2.size(), max_len = s1 + s2, c = ;
if (max_len == ) return "";
string res(max_len, '');
for (int i = ; i < max_len; i++) {
int bit_res = c;
for (int j = ; j <= i; j++) {
if (j < s1 && i - j < s2) bit_res += (num1[s1 - - j] - '') * (num2[s2 - - i + j] - '');
}
c = bit_res / ;
res[max_len - - i] = char(bit_res % + '');
}
int pos = ;
while (res[pos] == '') pos++;
return pos == res.size() ? "" : res.substr(pos);
}
};
29. Divide Two Integers
https://leetcode.com/problems/divide-two-integers/#/description
Divide two integers without using multiplication, division and mod operator. If it is overflow, return MAX_INT.
desc
二进制,位运算。时间复杂度是O(logN)。
class Solution {
public:
int divide(int dividend, int divisor) {
if (divisor == || (dividend == INT_MIN && divisor == -)) return INT_MAX;
int sign = (dividend > ) ^ (divisor > ) ? - : , res = , multi;
long long d = labs(dividend), s = labs(divisor), tmp;
while (d >= s) {
tmp = s;
multi = ;
while (d >= (tmp << )) {
tmp <<= ;
multi <<= ;
}
res += multi;
d -= tmp;
}
return res * sign;
}
};
12. Integer to Roman
https://leetcode.com/problems/integer-to-roman/#/description
阿拉伯数字转为罗马数字表示
class Solution {
public:
string intToRoman(int num) {
vector<string> m = {"", "M", "MM", "MMM"};
vector<string> c = {"", "C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM"};
vector<string> x = {"", "X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC"};
vector<string> i = {"", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX"};
return m[num / ] + c[num % / ] + x[num % / ] + i[num % ];
}
};
13. Roman to Integer
https://leetcode.com/problems/roman-to-integer/description/
是12题的逆过程。
class Solution {
public:
int romanToInt(string s) {
map<char, int> m = {{'I', }, {'V', }, {'X', }, {'L', }, {'C', }, {'D', }, {'M', }};
int res = ;
for (int i = ; i < s.size(); i++) {
if (i < s.size() - && m[s[i + ]] > m[s[i]]) res -= m[s[i]];
else res += m[s[i]];
}
return res;
}
};
567. Permutation in String
https://leetcode.com/problems/permutation-in-string/#/description
Given two strings s1 and s2, write a function to return true if s2 contains the permutation of s1. In other words, one of the first string's permutations is the substring of the second string. Example :
Input:s1 = "ab" s2 = "eidbaooo"
Output:True
Explanation: s2 contains one permutation of s1 ("ba").
Example :
Input:s1= "ab" s2 = "eidboaoo"
Output: False
Note:
The input strings only contain lower case letters.
The length of both given strings is in range [, ,].
desc
一个简单的滑动窗口的题目,没思路,真是菜!一刷AC,还要再刷!
class Solution {
private:
bool allZero(vector<int>& v) {
for (auto i : v) {
if (i) {
return false;
}
}
return true;
}
public:
bool checkInclusion(string s1, string s2) {
if (s1.size() > s2.size()) {
return false;
}
vector<int> status(, );
for (auto c: s1) {
status[c - 'a']++;
}
for (int i = ; i < s1.size(); i++) {
status[s2[i] - 'a']--;
}
if (allZero(status)) {
return true;
}
for (int i = s1.size(); i < s2.size(); i++) {
status[s2[i] - 'a']--;
status[s2[i - s1.size()] - 'a']++;
if (allZero(status)) {
return true;
}
}
return false;
}
};
532. K-diff Pairs in an Array
https://leetcode.com/problems/k-diff-pairs-in-an-array/#/description
Given an array of integers and an integer k, you need to find the number of unique k-diff pairs in the array. Here a k-diff pair is defined as an integer pair (i, j), where i and j are both numbers in the array and their absolute difference is k. Example :
Input: [, , , , ], k =
Output:
Explanation: There are two -diff pairs in the array, (, ) and (, ).
Although we have two 1s in the input, we should only return the number of unique pairs.
Example :
Input:[, , , , ], k =
Output:
Explanation: There are four -diff pairs in the array, (, ), (, ), (, ) and (, ).
Example :
Input: [, , , , ], k =
Output:
Explanation: There is one -diff pair in the array, (, ).
Note:
The pairs (i, j) and (j, i) count as the same pair.
The length of the array won't exceed 10,000.
All the integers in the given input belong to the range: [-1e7, 1e7].
desc
很简单,没有一次AC,再刷!
class Solution {
public:
int findPairs(vector<int>& nums, int k) {
if (nums.size() < ) {
return ;
}
sort(nums.begin(), nums.end());
int b = , e = , count = ;
while (b < e && e < nums.size()) {
if (nums[e] - nums[b] == k) {
count++;
do {
b++;
e++;
} while (nums[e] == nums[e - ] && nums[b] == nums[b - ]);
} else if (nums[e] - nums[b] < k) {
e++;
} else {
b++;
}
if (b == e) {
e++;
}
}
return count;
}
};
524. Longest Word in Dictionary through Deleting
https://leetcode.com/problems/longest-word-in-dictionary-through-deleting/#/description
Given a string and a string dictionary, find the longest string in the dictionary that can be formed by deleting some characters of the given string. If there are more than one possible results, return the longest word with the smallest lexicographical order. If there is no possible result, return the empty string. Example :
Input:
s = "abpcplea", d = ["ale","apple","monkey","plea"] Output:
"apple"
Example :
Input:
s = "abpcplea", d = ["a","b","c"] Output:
"a"
Note:
All the strings in the input will only contain lower-case letters.
The size of the dictionary won't exceed 1,000.
The length of all the strings in the input won't exceed 1,000.
desc
思路不是自己的。一刷因为多个变量在同一行中定义写法出错拿个CE!对于pj的增长方式还是没办法提出比较容易理解的模型。再刷!!
class Solution {
public:
string findLongestWord(string s, vector<string>& d) {
string ans;
for (int i = ; i < d.size(); i++) {
int pi = , pj = ;
for (; pi < s.size() && pj < d[i].size(); pi++) {
pj += s[pi] == d[i][pj];
}
if (pj == d[i].size() && (ans.size() < d[i].size() || (ans.size() == d[i].size() && d[i] < ans))) {
ans = d[i];
}
}
return ans;
}
};
3. Longest Substring Without Repeating Characters
https://leetcode.com/problems/longest-substring-without-repeating-characters/#/description
Given a string, find the length of the longest substring without repeating characters. Examples: Given "abcabcbb", the answer is "abc", which the length is . Given "bbbbb", the answer is "b", with the length of . Given "pwwkew", the answer is "wke", with the length of . Note that the answer must be a substring, "pwke" is a subsequence and not a substring.
desc
滑动窗口,双指针。使用一个长为256的vector记录每个char上次出现的位置,用start记录当前无重复元素子串的起始位置,窗口右侧遇到一个已经访问过的char,窗口左侧(start)移到改char上次出现位置的后一位。
class Solution {
public:
int lengthOfLongestSubstring(string s) {
vector<int> v(, -);
int start = , res = ;
for (int i = ; i < s.size(); i++) {
if (v[s[i]] >= start) start = v[s[i]] + ;
v[s[i]] = i;
res = max(res, i - start + );
}
return res;
}
};
557. Reverse Words in a String III
https://leetcode.com/problems/reverse-words-in-a-string-iii/#/description
Given a string, you need to reverse the order of characters in each word within a sentence while still preserving whitespace and initial word order. Example :
Input: "Let's take LeetCode contest"
Output: "s'teL ekat edoCteeL tsetnoc"
Note: In the string, each word is separated by single space and there will not be any extra space in the string.
desc
面试被难倒的一个问题,一刷没有AC,真是辣鸡!再刷!
class Solution {
public:
string reverseWords(string s) {
if (s.size() < ) {
return s;
}
for (int i = ; i < s.size(); i++) {
int j = i;
// cout << i << endl;
while (j < s.size() && s[j] != ' ') {
j++;
}
for (int k = ; k < (j - i) / ; k++) {
char temp = s[i + k];
s[i + k] = s[j - - k];
s[j - - k] = temp;
// swap(s[i + k], s[j - 1 - k]);
}
// cout << s << endl;
i = j;
}
return s;
}
};
520. Detect Capital
https://leetcode.com/problems/detect-capital/#/description
Given a word, you need to judge whether the usage of capitals in it is right or not. We define the usage of capitals in a word to be right when one of the following cases holds: All letters in this word are capitals, like "USA".
All letters in this word are not capitals, like "leetcode".
Only the first letter in this word is capital if it has more than one letter, like "Google".
Otherwise, we define that this word doesn't use capitals in a right way.
Example :
Input: "USA"
Output: True
Example :
Input: "FlaG"
Output: False
Note: The input will be a non-empty word consisting of uppercase and lowercase latin letters.
desc
一次AC。注意判断逻辑顺序。
class Solution {
public:
bool detectCapitalUse(string word) {
if (word.size() < ) {
return true;
}
if ('a' <= word[] && word[] <= 'z') {
for (int i = ; i < word.size(); i++) {
if ('A' <= word[i] && word[i] <= 'Z') {
return false;
}
}
return true;
} else {
if (word.size() == ) {
return true;
} else {
if (word[] <= 'Z' && word[] >= 'A') {
for (int i = ; i < word.size(); i++) {
if ('a' <= word[i] && word[i] <= 'z') {
return false;
}
}
return true;
} else {
for (int i = ; i < word.size(); i++) {
if ('A' <= word[i] && word[i] <= 'Z') {
return false;
}
}
return true;
}
}
}
}
};
541. Reverse String II
https://leetcode.com/problems/reverse-string-ii/#/description
Given a string and an integer k, you need to reverse the first k characters for every 2k characters counting from the start of the string. If there are less than k characters left, reverse all of them. If there are less than 2k but greater than or equal to k characters, then reverse the first k characters and left the other as original.
Example:
Input: s = "abcdefg", k =
Output: "bacdfeg"
Restrictions:
The string consists of lower English letters only.
Length of the given string and k will in the range [, ]
desc
一刷AC。
class Solution {
public:
string reverseStr(string s, int k) {
for (int i = ; i * * k < s.size(); i++) {
if (i * * k + k > s.size()) {
reverse(s.begin() + i * *k, s.end());
} else {
reverse(s.begin() + i * * k, s.begin() + i * * k + k);
}
}
return s;
}
};
434. Number of Segments in a String Add to List
https://leetcode.com/problems/number-of-segments-in-a-string/#/description
Count the number of segments in a string, where a segment is defined to be a contiguous sequence of non-space characters. Please note that the string does not contain any non-printable characters. Example: Input: "Hello, my name is John"
Output:
desc
一刷临界情况没写准,没AC。
class Solution {
public:
int countSegments(string s) {
int res = ;
for (int i = ; i < s.size();) {
while (s[i] == ' ' && i < s.size()) {
i++;
}
if (! (i < s.size())) {
return res;
}
while (s[i] != ' ' && i < s.size()) {
i++;
}
res++;
}
return res;
}
};
551. Student Attendance Record I
https://leetcode.com/problems/student-attendance-record-i/#/description
You are given a string representing an attendance record for a student. The record only contains the following three characters: 'A' : Absent.
'L' : Late.
'P' : Present.
A student could be rewarded if his attendance record doesn't contain more than one 'A' (absent) or more than two continuous 'L' (late). You need to return whether the student could be rewarded according to his attendance record. Example :
Input: "PPALLP"
Output: True
Example :
Input: "PPALLL"
Output: False
desc
一刷AC。
class Solution {
public:
bool checkRecord(string s) {
int a_count = , l_count = ;
for (auto c: s) {
if (c == 'A') {
a_count++;
l_count = ;
if (a_count > ) {
return false;
}
} else if (c == 'L') {
l_count++;
if (l_count > ) {
return false;
}
} else {
l_count = ;
}
}
return true;
}
};
459. Repeated Substring Pattern
https://leetcode.com/problems/repeated-substring-pattern/#/description
Given a non-empty string check if it can be constructed by taking a substring of it and appending multiple copies of the substring together. You may assume the given string consists of lowercase English letters only and its length will not exceed . Example :
Input: "abab" Output: True Explanation: It's the substring "ab" twice.
Example :
Input: "aba" Output: False
Example :
Input: "abcabcabcabc" Output: True Explanation: It's the substring "abc" four times. (And the substring "abcabc" twice.)
desc
不难,但是我的解法时间复杂度比较高,一刷没AC.解答区有时间复杂度为O(N)的DP算法。
class Solution {
public:
bool repeatedSubstringPattern(string s) {
if (s.size() < ) {
return false;
}
for(int i = ; i <= s.size(); i++) {
if (s.size() % i != ) {
continue;
}
int subSize = s.size() / i;
string subStr = s.substr(, subSize);
string tmp;
for (int i = ; i < s.size() / subSize; i++) {
tmp += subStr;
}
if (tmp == s) {
return true;
}
}
return false;
}
};
my solution
521. Longest Uncommon Subsequence I
https://leetcode.com/problems/longest-uncommon-subsequence-i/#/description
Given a group of two strings, you need to find the longest uncommon subsequence of this group of two strings. The longest uncommon subsequence is defined as the longest subsequence of one of these strings and this subsequence should not be any subsequence of the other strings. A subsequence is a sequence that can be derived from one sequence by deleting some characters without changing the order of the remaining elements. Trivially, any string is a subsequence of itself and an empty string is a subsequence of any string. The input will be two strings, and the output needs to be the length of the longest uncommon subsequence. If the longest uncommon subsequence doesn't exist, return -1. Example :
Input: "aba", "cdc"
Output:
Explanation: The longest uncommon subsequence is "aba" (or "cdc"),
because "aba" is a subsequence of "aba",
but not a subsequence of any other strings in the group of two strings.
Note: Both strings' lengths will not exceed 100.
Only letters from a ~ z will appear in input strings.
desc
一行完事,但是很绕!再刷!
class Solution {
public:
int findLUSlength(string a, string b) {
return a == b ? - : max(a.size(), b.size());
}
};
5. Longest Palindromic Substring
https://leetcode.com/problems/longest-palindromic-substring/#/description
Given a string s, find the longest palindromic substring in s. You may assume that the maximum length of s is . Example: Input: "babad" Output: "bab" Note: "aba" is also a valid answer.
Example: Input: "cbbd" Output: "bb"
desc
解法比较朴素,遍历每个字符,沿两侧展开,更新起始点和最大长度。一刷没AC,再刷!
class Solution {
public:
string longestPalindrome(string s) {
if (s.size() < ) {
return s;
}
int min_start = , max_len = ;
for (int i = ; i < s.size();) {
int k = i, j = i;
while (k < s.size() - && s[k + ] == s[k]) {
k++;
}
i = k + ;
while (k < s.size() - && j >= && s[k + ] == s[j - ]) {
k++;
j--;
}
if (k - j + > max_len) {
min_start = j;
max_len = k - j + ;
}
}
return s.substr(min_start, max_len);
}
};
DP解法,先判断是否为回文串,然后更新起始点,O(N^2)。
class Solution {
public:
string longestPalindrome(string s) {
int n = s.size(), start = , end = ;
if (n < ) return s;
vector<vector<bool>> dp(n, vector<bool>(n, false));
for (int i = ; i < n; i++) dp[i][i] = true;
for (int len = ; len <= n; len++) {
for (int i = ; i + len - < n; i++) {
int j = i + len - ;
dp[i][j] = s[i] == s[j] && (i + > j || dp[i + ][j - ]);
if (dp[i][j]) {start = i; end = j;}
}
}
return s.substr(start, end - start + );
}
};
9. Palindrome Number
https://leetcode.com/problems/palindrome-number/description/
双指针或者看逆数与原数是否相等,注意本题中负数不合法。
class Solution {
public:
bool isPalindrome(int x) {
if (x < ) return false;
int tmp = x, l = , r = ;
while (tmp > ) {
tmp /= ;
l *= ;
}
while(l > r) {
if (x / l % != x / r % ) return false;
l /= ; r *= ;
}
return true;
}
};
two pointers
385. Mini Parser
https://leetcode.com/problems/mini-parser/#/description
Given a nested list of integers represented as a string, implement a parser to deserialize it. Each element is either an integer, or a list -- whose elements may also be integers or other lists. Note: You may assume that the string is well-formed: String is non-empty.
String does not contain white spaces.
String contains only digits -, [, - ,, ].
Example : Given s = "", You should return a NestedInteger object which contains a single integer .
Example : Given s = "[123,[456,[789]]]", Return a NestedInteger object containing a nested list with elements: . An integer containing value .
. A nested list containing two elements:
i. An integer containing value .
ii. A nested list with one element:
a. An integer containing value .
desc
不算简单,用到istringstream,不好理解!子函数对流修改后,父函数要clear()才能得到正确的指针!一刷AC但是不太理解递归,再刷!
/**
* // This is the interface that allows for creating nested lists.
* // You should not implement it, or speculate about its implementation
* class NestedInteger {
* public:
* // Constructor initializes an empty nested list.
* NestedInteger();
*
* // Constructor initializes a single integer.
* NestedInteger(int value);
*
* // Return true if this NestedInteger holds a single integer, rather than a nested list.
* bool isInteger() const;
*
* // Return the single integer that this NestedInteger holds, if it holds a single integer
* // The result is undefined if this NestedInteger holds a nested list
* int getInteger() const;
*
* // Set this NestedInteger to hold a single integer.
* void setInteger(int value);
*
* // Set this NestedInteger to hold a nested list and adds a nested integer to it.
* void add(const NestedInteger &ni);
*
* // Return the nested list that this NestedInteger holds, if it holds a nested list
* // The result is undefined if this NestedInteger holds a single integer
* const vector<NestedInteger> &getList() const;
* };
*/
class Solution {
private:
NestedInteger deserialize(istringstream &in) {
int num;
if (in >> num) {
return NestedInteger(num);
}
in.clear();
in.get();
NestedInteger list;
while (in.peek() != ']') {
list.add(deserialize(in));
if (in.peek() == ',') {
in.get();
}
}
in.get();
return list;
} public:
NestedInteger deserialize(string s) {
istringstream in(s);
return deserialize(in);
}
};
6. ZigZag Conversion
https://leetcode.com/problems/zigzag-conversion/#/description
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 text, int nRows);
convert("PAYPALISHIRING", ) should return "PAHNAPLSIIGYIR".
desc
比较简单,一刷没AC,没有认真考虑边界条件。numRows为0直接返回原串即可。
class Solution {
public:
string convert(string s, int numRows) {
if (numRows == ) {
return s;
}
vector<string> vec(numRows, "");
for (int i = ; i * (numRows * - ) < s.size(); i++) {
int start = i * (numRows * - );
int tempSize = ;
if (s.size() >= (i + ) * (numRows * - ) ) {
tempSize = numRows * - ;
} else {
tempSize = s.size() - start;
}
for (int j = ; j < numRows && j < tempSize; j++) {
vec[j] += s[start + j];
}
for (int j = ; j + numRows < tempSize; j++) {
vec[numRows - - j] += s[start + j + numRows];
}
}
string res;
for (auto str: vec) {
res += str;
}
return res;
}
};
556. Next Greater Element III
https://leetcode.com/problems/next-greater-element-iii/#/description
Given a positive -bit integer n, you need to find the smallest -bit integer which has exactly the same digits existing in the integer n and is greater in value than n. If no such positive -bit integer exists, you need to return -. Example :
Input:
Output:
Example :
Input:
Output: -
不难,但是忘记怎么求下一个排列的算法了。标准库有api可以用!
class Solution {
public:
int nextGreaterElement(int n) {
string s = to_string(n);
next_permutation(s.begin(), s.end());
auto res = stoll(s);
return (res > INT_MAX || res <= n) ? - : res;
}
};
227. Basic Calculator II
https://leetcode.com/problems/basic-calculator-ii/#/description
Implement a basic calculator to evaluate a simple expression string. The expression string contains only non-negative integers, +, -, *, / operators and empty spaces . The integer division should truncate toward zero. You may assume that the given expression is always valid. Some examples:
"3+2*2" =
" 3/2 " =
" 3+5 / 2 " =
Note: Do not use the eval built-in library function.
istringstream非常好用,可以从中直接读取任意数据类型,读取字符串直接用getline操作。注意用op来对term进行正负修饰,只有第一次读入加号或者减号的时候需要。一刷没思路,二刷term的正负没写对位置。
class Solution {
public:
int calculate(string s) {
long long res = , tmp = ;
istringstream in("+" + s + "+");
char op;
while (in >> op) {
if (op == '+' || op == '-') {
res += tmp;
in >> tmp;
tmp *= (op == '+' ? : -);
} else if (op == '*' || op == '/') {
int t;
in >> t;
if (op == '*') tmp *= t;
else tmp /= t;
}
}
return res;
}
};
224. Basic Calculator
https://leetcode.com/problems/basic-calculator/description/
Implement a basic calculator to evaluate a simple expression string. The expression string may contain open ( and closing parentheses ), the plus + or minus sign -, non-negative integers and empty spaces . You may assume that the given expression is always valid. Some examples:
"1 + 1" =
" 2-1 + 2 " =
"(1+(4+5+2)-3)+(6+8)" =
Note: Do not use the eval built-in library function.
和227相似,稍难主要是括号的处理。使用signs的栈存储当前括号计算结果应该乘上的符号,sign只存储一个数字的符号。上题适合使用stringstream,本题不适合使用stringstream。
class Solution {
public:
int calculate(string s) {
int num = , res = , sign = ;
stack<int> signs;
signs.push();
for (auto c : s) {
if (c >= '' && c <= '') {
num = num * + c - '';
} else if (c == '+' || c == '-') {
res += num * signs.top() * sign;
sign = (c == '+' ? : -);
num = ;
} else if (c == '(') {
signs.push(signs.top() * sign);
sign = ;
} else if (c == ')'){
res += num * sign * signs.top();
signs.pop();
sign = ;
num = ;
}
}
if (num) res += num * sign * signs.top();
return res;
}
};
17. Letter Combinations of a Phone Number Add to List
https://leetcode.com/problems/letter-combinations-of-a-phone-number/#/description
Given a digit string, 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. Input:Digit string ""
Output: ["ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf"].
Note:
Although the above answer is in lexicographical order, your answer could be in any order you want.
DFS和BFS都可以做,我更喜欢BFS。应该有更好的解法。再刷注意使用更高效的算法。
class Solution {
public:
vector<string> letterCombinations(string digits) {
if (digits.size() == ) return vector<string> ();
unordered_map<int, string> m({{, "abc"}, {, "def"}, {, "ghi"}, {, "jkl"}, {, "mno"}, {, "pqrs"}, {, "tuv"}, {, "wxyz"}});
vector<string> res(, "");
string tmp;
for (char c : digits) {
int s = res.size();
for (int i = ; i < m[c - ''].size() - ; i++) {
for (int j = ; j < s; j++) {
tmp = res[j];
tmp.push_back(m[c - ''][i + ]);
res.push_back(tmp);
}
}
for (int j = ; j < s; j++) {
res[j].push_back(m[c - ''][]);
}
}
return res;
}
};
336. Palindrome Pairs
https://leetcode.com/problems/palindrome-pairs/#/description
Given a list of unique words, find all pairs of distinct indices (i, j) in the given list, so that the concatenation of the two words, i.e. words[i] + words[j] is a palindrome. Example :
Given words = ["bat", "tab", "cat"]
Return [[, ], [, ]]
The palindromes are ["battab", "tabbat"]
Example :
Given words = ["abcd", "dcba", "lls", "s", "sssll"]
Return [[, ], [, ], [, ], [, ]]
The palindromes are ["dcbaabcd", "abcddcba", "slls", "llssssll"]
想有个好点的算法比较难,还不太理解讨论区大神的算法,一刷没AC。忘记边界拿了WA,再刷!
class Solution {
public:
vector<vector<int>> palindromePairs(vector<string>& words) {
unordered_map<string, int> m;
vector<vector<int> > res;
for (int i = ; i < words.size(); i++) {
string k = words[i];
reverse(k.begin(), k.end());
m[k] = i;
}
if (m.find("") != m.end()) {
for (int i = ; i < words.size(); i++) {
if (words[i] == "") {
continue;
}
if (isPalindrome(words[i])) {
res.push_back({m[""], i});
}
}
}
for (int i = ; i < words.size(); i++) {
for (int j = ; j < words[i].size(); j++) {
string left = words[i].substr(, j);
string right = words[i].substr(j, words[i].size() - j);
if (m.find(left) != m.end() && isPalindrome(right) && m[left] != i) {
res.push_back({i, m[left]});
}
if (m.find(right) != m.end() && isPalindrome(left) && m[right] != i) {
res.push_back({m[right], i});
}
}
}
return res;
} bool isPalindrome(string s) {
if (s.size() == ) {
return true;
}
int i = , j = s.size() - ;
while (i < j) {
if (s[i++] != s[j--]) {
return false;
}
}
return true;
}
};
151. Reverse Words in a String
https://leetcode.com/problems/reverse-words-in-a-string/#/description
Given an input string, reverse the string word by word. For example,
Given s = "the sky is blue",
return "blue is sky the".
要注意一种变换:将整体反转之后,这个问题就变成了将句子内单词逐个反转的题目!这个规律至少用了3次了!一刷没有AC。不记得erase是否为string的成员函数CE!这个题目非常经典,这个算法也非常好,再刷!
class Solution {
public:
void reverseWords(string &s) {
reverse(s.begin(), s.end());
int idx = ;
for (int i = ; i < s.size(); i++) {
if (s[i] != ' ') {
if(idx != ) {
s[idx++] = ' ';
}
int j = i;
while (j < s.size() && s[j] != ' ') {
s[idx++] = s[j++];
}
reverse(s.begin() + idx - (j - i), s.begin() + idx);
i = j;
}
}
s.erase(s.begin() + idx, s.end());
}
};
539. Minimum Time Difference
https://leetcode.com/problems/minimum-time-difference/#/description
Given a list of -hour clock time points in "Hour:Minutes" format, find the minimum minutes difference between any two time points in the list. Example :
Input: ["23:59","00:00"]
Output:
Note:
The number of time points in the given list is at least and won't exceed 20000.
The input time is legal and ranges from : to :.
一刷没AC,一开始没看懂题意导致WA。看了解答区的算法手写各种CE!再刷!
class Solution {
public:
int findMinDifference(vector<string>& timePoints) {
sort(timePoints.begin(), timePoints.end());
int minDiff = INT_MAX, n = timePoints.size();
for (int i = ; i < timePoints.size(); i++) {
int diff = timeDiff(timePoints[(i - + n) % n], timePoints[i]);
diff = min(diff, - diff);
minDiff = min(diff, minDiff);
}
return minDiff;
} int timeDiff(string t1, string t2) {
int t1h = stoi(t1.substr(, )), t1m = stoi(t1.substr(, ));
int t2h = stoi(t2.substr(, )), t2m = stoi(t2.substr(, ));
return abs((t1h - t2h) * + (t1m - t2m)); }
};
583. Delete Operation for Two Strings Add to List
https://leetcode.com/problems/delete-operation-for-two-strings/#/description
Given two words word1 and word2, find the minimum number of steps required to make word1 and word2 the same, where in each step you can delete one character in either string. Example :
Input: "sea", "eat"
Output:
Explanation: You need one step to make "sea" to "ea" and another step to make "eat" to "ea".
Note:
The length of given words won't exceed 500.
Characters in given words can only be lower-case letters.
一刷没有AC,min函数只能比较两个数,编译错误。DP算法不太懂,再刷!!二刷没有一次AC,j初始化错误。没完全理解算法,再刷!自己手动运行了几遍代码,终于搞懂了。dp的元素矩阵表示应该删除的字符个数,最外围那一行和列表示一个串为子串,而另外一个串为空串!但是没动手再刷一次!再刷!三刷一次AC。
class Solution {
public:
int minDistance(string word1, string word2) {
int m = word1.size(), n = word2.size();
vector <vector<int> > dp(m + , vector<int> (n + , ));
for(int i = m - ; i >= ; i--) {
dp[i][n] = dp[i + ][n] + ;
}
for (int j = n - ; j >= ; j--) {
dp[m][j] = dp[m][j + ] + ;
}
for (int i = m - ; i >= ; i--) {
for (int j = n - ; j >= ; j--) {
int dela = + dp[i + ][j];
int delb = + dp[i][j + ];
int delab = (word1[i] == word2[j] ? : ) + dp[i + ][j + ];
dp[i][j] = min(dela, min(delb, delab));
}
}
return dp[][];
}
};
468. Validate IP Address
https://leetcode.com/problems/validate-ip-address/#/description
Write a function to check whether an input string is a valid IPv4 address or IPv6 address or neither. IPv4 addresses are canonically represented in dot-decimal notation, which consists of four decimal numbers, each ranging from to , separated by dots ("."), e.g.,172.16.254.1; Besides, leading zeros in the IPv4 is invalid. For example, the address 172.16.254.01 is invalid. IPv6 addresses are represented as eight groups of four hexadecimal digits, each group representing bits. The groups are separated by colons (":"). For example, the address :0db8:85a3:::8a2e:: is a valid one. Also, we could omit some leading zeros among four hexadecimal digits and some low-case characters in the address to upper-case ones, so :db8:85a3:::8A2E:: is also a valid IPv6 address(Omit leading zeros and using upper cases). However, we don't replace a consecutive group of zero value with a single empty group using two consecutive colons (::) to pursue simplicity. For example, 2001:0db8:85a3::8A2E:0370:7334 is an invalid IPv6 address. Besides, extra leading zeros in the IPv6 is also invalid. For example, the address :0db8:85a3:::8a2e:: is invalid. Note: You may assume there is no extra space or special characters in the input string. Example :
Input: "172.16.254.1" Output: "IPv4" Explanation: This is a valid IPv4 address, return "IPv4".
Example :
Input: "2001:0db8:85a3:0:0:8A2E:0370:7334" Output: "IPv6" Explanation: This is a valid IPv6 address, return "IPv6".
Example :
Input: "256.256.256.256" Output: "Neither" Explanation: This is neither a IPv4 address nor a IPv6 address.
一刷没AC,getline在这个题目中有妙用!题目不难,但是边界条件非常多!坑很多!再刷!
class Solution {
private:
bool validIPv4(string &s) {
if (!isdigit(s.back())) {
return false;
}
stringstream ss(s);
string buf;
int count = ;
while (getline(ss, buf, '.')) {
if (buf.size() == ) {
return false;
}
if ((buf[] == '' && buf.size() > ) || buf.size() > ) {
return false;
}
for (auto c: buf) {
if (!isdigit(c)) {
return false;
}
}
int n = stoi(buf);
if (n > || n < ) {
return false;
}
count++;
}
return count == ;
} bool validIPv6(string &s) {
if (s.back() == ':') {
return false;
}
stringstream ss(s);
int count = ;
string buf;
while (getline(ss, buf, ':')) {
if(buf.size() == || buf.size() > ) {
return false;
}
for (auto c: buf) {
c = tolower(c);
if (!isalnum(c)) {
return false;
} else if (!isdigit(c) && !(c <= 'f' && c >= 'a')) {
return false;
}
}
count++;
}
return count == ;
} public:
string validIPAddress(string IP) {
string res;
if (IP.size() == ) {
return "Neither";
}
bool isv4 = false, isv6 = false;
int firstDot = IP.find_first_of('.');
int firstCol = IP.find_first_of(':');
if (firstDot > ) {
isv4 = validIPv4(IP);
} else if (firstCol > ) {
isv6 = validIPv6(IP);
}
if (!isv4 && !isv6) {
res = "Neither";
} else if (isv4) {
res = "IPv4";
} else {
res = "IPv6";
}
return res;
}
};
522. Longest Uncommon Subsequence II
https://leetcode.com/problems/longest-uncommon-subsequence-ii/#/description
Given a list of strings, you need to find the longest uncommon subsequence among them. The longest uncommon subsequence is defined as the longest subsequence of one of these strings and this subsequence should not be any subsequence of the other strings. A subsequence is a sequence that can be derived from one sequence by deleting some characters without changing the order of the remaining elements. Trivially, any string is a subsequence of itself and an empty string is a subsequence of any string. The input will be a list of strings, and the output needs to be the length of the longest uncommon subsequence. If the longest uncommon subsequence doesn't exist, return -1. Example :
Input: "aba", "cdc", "eae"
Output:
Note: All the given strings' lengths will not exceed 10.
The length of the given list will be in the range of [, ].
思路不是自己的,一刷废了很大劲没AC。用了两种方法,直接构造带有cmp函数的map失效,还没弄明白原因!再刷!
class Solution {
public:
int findLUSlength(vector<string>& strs) {
map< string, int> m;
for (auto s: strs) {
m[s]++;
}
vector< pair< string, int > > vec(m.begin(), m.end());
sort(vec.begin(), vec.end(), myCompare);
for (auto it = vec.begin(); it != vec.end(); it++) {
if (it->second == ) {
auto jit = vec.begin();
for (; jit != it; jit++) {
if (s1IsSubstrOfS2(it->first, jit->first)) {
break;
}
}
if (jit->first == it->first) {
return it->first.size();
}
}
}
return -;
} bool s1IsSubstrOfS2(const string& s1, const string& s2) {
for(int i = , j = ; i < s1.size(); i++) {
while (j < s2.size() && s1[i] != s2[j]) {
j++;
}
if (j == s2.size()) {
return false;
}
j++;
}
return true;
} static bool myCompare(const pair<string, int>& p1, const pair<string, int>& p2) {
return p1.first.size() > p2.first.size();
}
};
91. Decode Ways
https://leetcode.com/problems/decode-ways/#/description
A message containing letters from A-Z is being encoded to numbers using the following mapping: 'A' ->
'B' ->
...
'Z' ->
Given an encoded message containing digits, determine the total number of ways to decode it. For example,
Given encoded message "", it could be decoded as "AB" ( ) or "L" (). The number of ways decoding "" is .
DP,注意处理非法输入。
class Solution {
public:
int numDecodings(string s) {
if (s.size() < ) return ;
vector<int> dp(s.size() + , );
dp[] = ;
for (int i = ; i <= s.size(); i++) {
if (dp[i - ] == ) return ;
dp[i] += s[i - ] == '' ? : dp[i - ];
if (i < ) continue;
int sum = (s[i - ] - '') * + s[i - ] - '';
dp[i] += (sum <= && sum >= ) ? dp[i - ] : ;
}
return dp[s.size()];
}
};
dp
71. Simplify Path
https://leetcode.com/problems/simplify-path/#/description
Given an absolute path for a file (Unix-style), simplify it. For example,
path = "/home/", => "/home"
path = "/a/./b/../../c/", => "/c"
click to show corner cases.
stack。用vector代替stack更简单,stringstream要用熟,getline(stream, buffer, char)的第三个参数表示分隔符。最后多出来一个"/"要去掉。
class Solution {
public:
string simplifyPath(string path) {
string res = "/", buffer;
vector<string> s;
stringstream ss(path);
while (getline(ss, buffer, '/')) {
if (buffer == "" || buffer == ".") continue;
else if (buffer == "..") {
if (!s.empty()) s.pop_back();
}
else s.push_back(buffer);
}
for (auto p : s) res += (p + "/");
if (res.size() > ) res.pop_back();
return res;
}
};
stack
93. Restore IP Addresses
https://leetcode.com/problems/restore-ip-addresses/#/description
Given a string containing only digits, restore it by returning all possible valid IP address combinations. For example:
Given "", return ["255.255.11.135", "255.255.111.35"]. (Order does not matter)
DFS。count记录ip段数,start记录起始位。
class Solution {
public:
vector<string> restoreIpAddresses(string s) {
vector<string> res;
string path = "";
dfs(s, res, , path, );
return res;
}
void dfs(string& s, vector<string>& res, int c, string p, int start) {
if (start > s.size() || c > ) return;
if (c == && start == s.size()) {
res.push_back(p);
return;
}
for (int i = ; i < && i + start <= s.size(); i++) {
string a = s.substr(start, i);
if ((i > && a[] == '') || (stoi(a) > )) break;
dfs(s, res, c + , p + a + (c == ? "" : "."), start + i);
}
}
};
22. Generate Parentheses
https://leetcode.com/problems/generate-parentheses/#/description
Given n pairs of parentheses, write a function to generate all combinations of well-formed parentheses. For example, given n = , a solution set is: [
"((()))",
"(()())",
"(())()",
"()(())",
"()()()"
]
dfs,左括号只要有剩余就可以选,右括号只有在已生成的串中左括号多于右括号才可以选。
class Solution {
public:
vector<string> generateParenthesis(int n) {
vector<string> res;
string path;
dfs(res, path, n, n);
return res;
}
void dfs(vector<string>& res, string path, int l, int r) {
if (!l && !r) {
res.push_back(path);
return;
}
if (l > ) dfs(res, path + "(", l - , r);
if (l < r) dfs(res, path + ")", l, r - );
}
};
475. Heaters
https://leetcode.com/problems/heaters/#/description
Winter is coming! Your first job during the contest is to design a standard heater with fixed warm radius to warm all the houses. Now, you are given positions of houses and heaters on a horizontal line, find out minimum radius of heaters so that all houses could be covered by those heaters. So, your input will be the positions of houses and heaters seperately, and your expected output will be the minimum radius standard of heaters. Note:
Numbers of houses and heaters you are given are non-negative and will not exceed .
Positions of houses and heaters you are given are non-negative and will not exceed ^.
As long as a house is in the heaters' warm radius range, it can be warmed.
All the heaters follow your radius standard and the warm radius will the same.
Example :
Input: [,,],[]
Output:
Explanation: The only heater was placed in the position , and if we use the radius standard, then all the houses can be warmed.
Example :
Input: [,,,],[,]
Output:
Explanation: The two heater was placed in the position and . We need to use radius standard, then all the houses can be warmed.
比较简单,但是没有好的思路。一刷没有一次AC,而是各种CE!再刷!从解答区选择的思路也不是最好的。二刷没有一次AC,不太懂upper_bound和lower_bound的区别拿了WA,再刷!
class Solution {
public:
int findRadius(vector<int>& houses, vector<int>& heaters) {
sort(heaters.begin(), heaters.end());
int minR = ;
for (auto h: houses) {
int curR = INT_MAX;
auto high = lower_bound(heaters.begin(), heaters.end(), h);
if (high != heaters.end()) {
curR = *high - h;
}
if (high != heaters.begin()) {
auto low = high - ;
curR = min(curR, h - *low);
}
minR = max(minR, curR);
}
return minR;
}
};
436. Find Right Interval
https://leetcode.com/problems/find-right-interval/#/description
Given a set of intervals, for each of the interval i, check if there exists an interval j whose start point is bigger than or equal to the end point of the interval i, which can be called that j is on the "right" of i. For any interval i, you need to store the minimum interval j's index, which means that the interval j has the minimum start point to build the "right" relationship for interval i. If the interval j doesn't exist, store - for the interval i. Finally, you need output the stored value of each interval as an array. Note:
You may assume the interval's end point is always bigger than its start point.
You may assume none of these intervals have the same start point.
Example :
Input: [ [,] ] Output: [-] Explanation: There is only one interval in the collection, so it outputs -.
Example :
Input: [ [,], [,], [,] ] Output: [-, , ] Explanation: There is no satisfied "right" interval for [,].
For [,], the interval [,] has minimum-"right" start point;
For [,], the interval [,] has minimum-"right" start point.
Example :
Input: [ [,], [,], [,] ] Output: [-, , -] Explanation: There is no satisfied "right" interval for [,] and [,].
For [,], the interval [,] has minimum-"right" start point.
比较简单,很久没刷,手很生,一刷没AC,各种CE,WA和RE,思路是对的,但是时间复杂度太高。解答区的算法很好,值得借鉴,但是思路不是自己的,再刷!
/**
* Definition for an interval.
* struct Interval {
* int start;
* int end;
* Interval() : start(0), end(0) {}
* Interval(int s, int e) : start(s), end(e) {}
* };
*/
class Solution {
public:
vector<int> findRightInterval(vector<Interval>& intervals) {
vector<int> res;
map<int, int> m;
for (int i = ; i < intervals.size(); i++) {
m[intervals[i].start] = i;
}
for (auto interval: intervals) {
auto itr = m.lower_bound(interval.end);
if (itr == m.end()) {
res.push_back(-);
} else {
res.push_back(itr->second);
}
}
return res;
}
};
300. Longest Increasing Subsequence
https://leetcode.com/problems/longest-increasing-subsequence/#/description
Given an unsorted array of integers, find the length of longest increasing subsequence. For example,
Given [, , , , , , , ],
The longest increasing subsequence is [, , , ], therefore the length is . 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(n2) complexity. Follow up: Could you improve it to O(n log n) time complexity?
一刷AC,使用patient sort算法,时间复杂度为O(NLOGN),但是不太理解。二刷一次AC,仍然不太理解。三刷使用java刷,算法使用一维DP,时间复杂度为O(N^2),效率略低,思路很简单,没AC,要注意重复数字不能计入length。patient sort是专门应对这个题的算法!和95相似,这两个问题的DP算法都有一点弯。四刷一次AC。
class Solution {
public:
int lengthOfLIS(vector<int>& nums) {
vector<int> res;
for (auto n : nums) {
auto ptr = lower_bound(res.begin(), res.end(), n);
if ( ptr == res.end() ) {
res.push_back(n);
} else {
*ptr = n;
}
}
return res.size();
}
};
32. Longest Valid Parentheses
https://leetcode.com/problems/longest-valid-parentheses/description/
Given a string containing just the characters '(' and ')', find the length of the longest valid (well-formed) parentheses substring. For "(()", the longest valid parentheses substring is "()", which has length = . Another example is ")()())", where the longest valid parentheses substring is "()()", which has length = .
一维DP,每一个元素记录以当前字符结尾的最长合法串的长度。
1. s[i] == '(', dp[i] = 0;
2. s[i] == ')', 如果s[i - 1] == '(' 则dp[i] = dp[i- 2] + 2, 如果s[i - dp[i-1]-1] == '(', 则dp[i] = dp[i-dp[i-1]-2] + dp[i-1]+2;
class Solution {
public:
int longestValidParentheses(string s) {
int ss = s.size(), res = ;
vector<int> dp(ss + , );
for (int i = ; i <= ss; i++) {
if (s[i - ] == ')') {
if (i > && s[i - ] == '(') dp[i] = dp[i - ] + ;
else if (i > && s[i - dp[i - ] - ] == '(') dp[i] = dp[i - dp[i - ] - ] + dp[i - ] + ;
res = max(res, dp[i]);
}
}
return res;
}
};
275. H-Index II
https://leetcode.com/problems/h-index-ii/#/description
Follow up for H-Index: What if the citations array is sorted in ascending order? Could you optimize your algorithm?
是274的附加题。题意很难懂,真的很难懂!很久没刷,找找感觉先!一刷各种错误,有CE也有WA,再刷!
class Solution {
public:
int hIndex(vector<int>& citations) {
int s = citations.size();
int low = , high = s -, mid;
while (low <= high) {
mid = low + ((high - low) >> );
if (citations[mid] == s - mid) {
return citations[mid];
} else if (citations[mid] > s - mid) {
high = mid - ;
} else {
low = mid + ;
}
}
return s - high - ;
}
};
378. Kth Smallest Element in a Sorted Matrix
https://leetcode.com/problems/kth-smallest-element-in-a-sorted-matrix/description/
Given a n x n matrix where each of the rows and columns are sorted in ascending order, find the kth smallest element in the matrix. Note that it is the kth smallest element in the sorted order, not the kth distinct element. Example: matrix = [
[ , , ],
[, , ],
[, , ]
],
k = , return .
Note:
You may assume k is always valid, ≤ k ≤ n2.
不算难,但是要找到二分查找中间的判定条件比较困难!看了一遍大神解法之后,一刷AC,但是对算法了解其实没那么深,尤其是如何将一个不在matrix中的值逼近到在matrix中的值。二刷对算法理解更透彻一些,对运算优先级把握不准,得了WA。再刷!
class Solution {
public:
int kthSmallest(vector<vector<int>>& matrix, int k) {
int n = matrix.size();
int low = matrix[][], high = matrix[n - ][n -];
int mid = ;
while (low < high) {
mid = low + ( (high - low) >> );
int num = ;
for (int i = ; i < n; i++) {
num += upper_bound(matrix[i].begin(), matrix[i].end(), mid) - matrix[i].begin();
}
if (num < k) {
low = mid + ;
} else {
high = mid;
}
}
return low;
}
};
392. Is Subsequence
https://leetcode.com/problems/is-subsequence/description/
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 ~= ,) string, and s is a short string (<=). 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 :
s = "abc", t = "ahbgdc" Return true. Example :
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?
不难,一刷AC,O(N)复杂度。Follow up需要二分查找,discuss区有java代码可以研究一下!以后刷可以直接看follow up!
class Solution {
public:
bool isSubsequence(string s, string t) {
int m = s.size(), n = t.size();
if (m > n) {
return false;
}
int i = , j = ;
for (; i < m && j < n; j++) {
if (s[i] == t[j]) {
i++;
}
}
return i == m;
}
};
658. Find K Closest Elements
https://leetcode.com/problems/find-k-closest-elements/description/
Given a sorted array, two integers k and x, find the k closest elements to x in the array. The result should also be sorted in ascending order. If there is a tie, the smaller elements are always preferred. Example :
Input: [,,,,], k=, x=
Output: [,,,]
Example :
Input: [,,,,], k=, x=-
Output: [,,,]
Note:
The value k is positive and will always be smaller than the length of the sorted array.
Length of the given array is positive and will not exceed
Absolute value of elements in the array and x will not exceed
不太难,一刷没AC,思路大致正确但是实现有些细节错误!对lower_bound和upper_bound理解不太对,导致WA。lower_bound得到第一个不小于val的元素的迭代器,而upper_bound得到第一个大于val的元素的迭代器。判断条件有精妙,没能完全理解,再刷!
class Solution {
public:
vector<int> findClosestElements(vector<int>& arr, int k, int x) {
int index = lower_bound(arr.begin(), arr.end(), x) - arr.begin();
int low = index - , high = index;
while(k--) {
(low < || (high < arr.size() && abs(arr[high] - x) < abs(arr[low] - x)) ) ? high++ : low--;
}
return vector<int> (arr.begin() + low + , arr.begin() + high);
}
};
671. Second Minimum Node In a Binary Tree
https://leetcode.com/contest/leetcode-weekly-contest-48/problems/second-minimum-node-in-a-binary-tree/
Given a non-empty special binary tree consisting of nodes with the non-negative value, where each node in this tree has exactly two or zero sub-node. If the node has two sub-nodes, then this node's value is the smaller value among its two sub-nodes. Given such a binary tree, you need to output the second minimum value in the set made of all the nodes' value in the whole tree. If no such second minimum value exists, output - instead. Example :
Input: / \ / \ Output:
Explanation: The smallest value is , the second smallest value is .
Example :
Input: / \ Output: -
Explanation: The smallest value is , but there isn't any second smallest value.
Discuss
是数组求第N大元素的变形,只是使用的数据结构变了,核心算法思想没变,不难,递归解决,但是花了很长时间!
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
int findSecondMinimumValue(TreeNode* root) {
int min_ele = root->val, sec_min = -;
if (!root->left) {
return sec_min;
} else {
if (root->left->val != root->val && root->right->val != root->val) {
return min(root->left->val, root->right->val);
} else {
int sec_min_left = root->left->val;
int sec_min_right = root->right->val;
if (root->left->val == root->val) {
sec_min_left = findSecondMinimumValue(root->left);
}
if (root->right->val == root->val) {
sec_min_right = findSecondMinimumValue(root->right);
}
if (sec_min_left == - && sec_min_right == -) {
return -;
} else if (sec_min_left == -) {
return sec_min_right;
} else if (sec_min_right == -) {
return sec_min_left;
} else {
return min(sec_min_left, sec_min_right);
} }
}
}
};
669. 669. Trim a Binary Search Tree
https://leetcode.com/contest/leetcode-weekly-contest-48/problems/trim-a-binary-search-tree/
Given a binary search tree and the lowest and highest boundaries as L and R, trim the tree so that all its elements lies in [L, R] (R >= L). You might need to change the root of the tree, so the result should return the new root of the trimmed binary search tree. Example :
Input: / \ L =
R = Output: \ Example :
Input: / \ \ / L =
R = Output: / /
不难,简单的递归题。怪自己总是把问题忘难了想。
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
TreeNode* trimBST(TreeNode* root, int L, int R) {
if (!root) {
return root;
} else {
if (root->val < L) {
root = trimBST(root->right, L, R);
} else if (root->val > R) {
root = trimBST(root->left, L, R);
} else {
root->left = trimBST(root->left, L, R);
root->right = trimBST(root->right, L, R);
}
return root;
}
}
};
670. Maximum Swap
https://leetcode.com/contest/leetcode-weekly-contest-48/problems/maximum-swap/
Given a non-negative integer, you could swap two digits at most once to get the maximum valued number. Return the maximum valued number you could get. Example :
Input:
Output:
Explanation: Swap the number and the number .
Example :
Input:
Output:
Explanation: No swap.
Note:
The given number is in the range [, ]
不难,但是我的方法不太好,应该有很好很简单的方法,可以专门研究一下discuss区的好方法!
class Solution {
public:
int maximumSwap(int num) {
if(num < ) {
return num;
}
int s = (int)log10(double(num)) + ;
vector<int> v;
while (num) {
v.push_back(num % );
num /= ;
}
int max_num = num;
for (int i = ; i < s; i++) {
for (int j = i; j < s; j++) {
swap(v[i], v[j]);
int tmp = ;
for (int k = ; k < s; k++) {
tmp += v[k] * (int)pow(, k);
}
swap(v[i], v[j]);
max_num = max(max_num, tmp);
}
}
return max_num;
}
};
672. Bulb Switcher II
https://leetcode.com/contest/leetcode-weekly-contest-48/problems/bulb-switcher-ii/
There is a room with n lights which are turned on initially and buttons on the wall. After performing exactly m unknown operations towards buttons, you need to return how many different kinds of status of the n lights could be. Suppose n lights are labeled as number [, , ..., n], function of these buttons are given below: Flip all the lights.
Flip lights with even numbers.
Flip lights with odd numbers.
Flip lights with (3k + ) numbers, k = , , , ...
Example :
Input: n = , m = .
Output:
Explanation: Status can be: [on], [off]
Example :
Input: n = , m = .
Output:
Explanation: Status can be: [on, off], [off, on], [off, off]
Example :
Input: n = , m = .
Output:
Explanation: Status can be: [off, on, off], [on, off, on], [off, off, off], [off, on, on].
Note: n and m both fit in range [, ]. Discuss
一道规律题,挺难的,没思路,也没有发现规律,讨论区算法很简单,但是不是很理解!需要再理解一下!
class Solution {
public:
int flipLights(int n, int m) {
if (n == || m == ) {
return ;
}
if (n == ) {
return ;
}
if (n == ) {
return m == ? : ;
}
if (m == ) {
return ;
}
return m == ? : ;
}
};
222. Count Complete Tree Nodes
https://leetcode.com/problems/count-complete-tree-nodes/description/
Given a complete binary tree, count the number of nodes. Definition of a complete binary tree from Wikipedia:
In a complete binary tree every level, except possibly the last, is completely filled, and all nodes in the last level are as far left as possible. It can have between and 2h nodes inclusive at the last level h.
不难,很快有思路了,但是折腾了2小时,遇到各种错误,而且算法效率非常低!再刷!但是通过这道题更深的理解了二分查找算法。判断条件是更新high还是low只跟mid的计算方式有关,无论什么时候,区间一定要包含答案,这是原则!按照我的书写习惯,low不会比high大,终止情况是low = high = mid!
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
int countNodes(TreeNode* root) {
if (!root) {
return ;
}
TreeNode* tmp = root;
int l = ;
while (tmp) {
l++;
tmp = tmp->left;
}
int low = << (l - ), high = ( << l) - ;
int mid = ;
while (low < high) {
mid = low + ((high - low + ) >> );
int i = mid;
vector<int> v;
while (i) {
v.push_back(i % );
i /= ;
}
v.pop_back();
auto iter = v.rbegin();
tmp = root;
while (iter != v.rend() && tmp) {
if (*iter == ) {
tmp = tmp->left;
} else {
tmp = tmp->right;
}
iter++;
}
if (!tmp) {
high = mid - ;
} else {
low = mid;
}
}
return low;
}
};
Discuss区的大部分算法使用递归,实现了一种递归算法,一刷AC,不可思议的是使用递归竟然能干掉50%的算法!
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
int countNodes(TreeNode* root) {
if (!root) {
return ;
}
TreeNode* l = root;
TreeNode* r = root;
int hl = , hr = ;
while (l) {
l = l->left;
hl++;
}
while (r) {
r = r->right;
hr++;
}
if (hl == hr) {
return (int)pow(, hr) - ;
}
return + countNodes(root->left) + countNodes(root->right);
}
};
230. Kth Smallest Element in a BST
https://leetcode.com/problems/kth-smallest-element-in-a-bst/description/
Given a binary search tree, write a function kthSmallest to find the kth smallest element in it. Note:
You may assume k is always valid, ≤ k ≤ BST's total elements. Follow up:
What if the BST is modified (insert/delete operations) often and you need to find the kth smallest frequently? How would you optimize the kthSmallest routine?
一刷计算比mid值小的节点个数时逻辑出错,得了WA,再刷!用VS在本地debug就是方便,终于不用自己写很多cout了,而且快了很多!算法效率比较低,还有follow up!后面再刷要注意这两个问题。二刷使用非递归的基于树的中序遍历的方法一次AC,效率高出很多,再刷一次,深入理解BST的中序遍历过程,尤其是非递归方法。
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
int kthSmallest(TreeNode* root, int k) {
int low = root->val, high = root->val;
TreeNode* l = root, *r = root;
while (l) {
low = l->val;
l = l->left;
}
while (r) {
high = r->val;
r = r->right;
}
int mid = root->val;
while (low < high) {
mid = low + ((high - low) >> );
if (countLE(root, mid) < k) {
low = mid + ;
} else {
high = mid;
}
}
return low;
} int countLE(TreeNode* root, int mid) {
if (!root) {
return ;
} else {
int num = ;
if (mid < root->val) {
num += countLE(root->left, mid);
} else {
num += countLE(root->left, mid) + + countLE(root->right, mid);
}
return num;
}
}
};
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
int kthSmallest(TreeNode* root, int k) {
stack<TreeNode*> s;
while (root || !s.empty()) {
while (root) {
s.push(root);
root = root->left;
}
root = s.top();
s.pop();
if (--k == ) {
break;
}
root = root->right;
}
return root->val;
}
};
no_recursion
401. Binary Watch
https://leetcode.com/problems/binary-watch/description/
A binary watch has LEDs on the top which represent the hours (-), and the LEDs on the bottom represent the minutes (-). Each LED represents a zero or one, with the least significant bit on the right. For example, the above binary watch reads "3:25". Given a non-negative integer n which represents the number of LEDs that are currently on, return all possible times the watch could represent. Example: Input: n =
Return: ["1:00", "2:00", "4:00", "8:00", "0:01", "0:02", "0:04", "0:08", "0:16", "0:32"]
Note:
The order of output does not matter.
The hour must not contain a leading zero, for example "01:00" is not valid, it should be "1:00".
The minute must be consist of two digits and may contain a leading zero, for example "10:2" is not valid, it should be "10:02".
一刷没好的思路,看了discuss区之后,发现真的是直接遍历解空间!由于不理解表的的实际运行换算进制搞错得了WA,再刷!
class Solution {
public:
vector<string> readBinaryWatch(int num) {
vector<string> v;
for (int i = ; i < ; i++) {
for (int j = ; j < ; j++) {
bitset<> bits(i * + j);
if (bits.count() == num) {
string min = to_string(j);
if (j < ) {
min = "" + min;
}
v.push_back(to_string(i) + ":" + min);
}
}
}
return v;
}
};
46. Permutations
https://leetcode.com/problems/permutations/description/
Given a collection of distinct numbers, return all possible permutations. For example,
[,,] have the following permutations:
[
[,,],
[,,],
[,,],
[,,],
[,,],
[,,]
]
dfs, 78,90,46,47,39,40,131,132,77都是简单套路题。面试趋势是这种题目变为解决问题其中的一步。
class Solution {
public:
vector<vector<int>> permute(vector<int>& nums) {
vector<vector<int>> res;
vector<int> path;
map<int, int> visit;
dfs(nums, res, path, visit);
return res;
} void dfs(vector<int>& nums, vector<vector<int>>& res, vector<int>& path, map<int, int>& visit) {
if (path.size() == nums.size()) {
res.push_back(path);
return;
}
for (int n : nums) {
if (!visit[n] > ) {
path.push_back(n);
visit[n] = ;
dfs(nums, res, path, visit);
path.pop_back();
visit[n] = ;
}
}
}
};
dfs
47. Permutations II
https://leetcode.com/problems/permutations-ii/description/
Given a collection of numbers that might contain duplicates, return all possible unique permutations. For example,
[,,] have the following unique permutations:
[
[,,],
[,,],
[,,]
]
比46要难,去重可以使用frequency,将只考虑重复元素的第一个元素,重复次数用频率计数。排列、组合、组合和都属于01背包问题,理解要加强。
class Solution {
public:
vector<vector<int>> permuteUnique(vector<int>& nums) {
vector<vector<int>> res;
vector<int> path;
map<int, int> freq;
for (auto n : nums) freq[n]++;
sort(nums.begin(), nums.end());
dfs(nums, res, path, freq);
return res;
}
void dfs(vector<int>& nums, vector<vector<int>>& res, vector<int>& path, map<int, int>& freq) {
if (path.size() == nums.size()) {
res.push_back(path);
return;
}
for (int i = ; i < nums.size(); i++) {
if (count(path.begin(), path.end(), nums[i]) < freq[nums[i]] && !(i > && nums[i] == nums[i - ])) {
path.push_back(nums[i]);
dfs(nums, res, path, freq);
path.pop_back();
}
}
}
};
dfs
90. Subsets II
https://leetcode.com/problems/subsets-ii/description/
Given a collection of integers that might contain duplicates, nums, return all possible subsets. Note: The solution set must not contain duplicate subsets. For example,
If nums = [,,], a solution is: [
[],
[],
[,,],
[,],
[,],
[]
]
dfs,先排序,对着解空间写递归,注意去重。
class Solution {
public:
vector<vector<int>> subsetsWithDup(vector<int>& nums) {
sort(nums.begin(), nums.end());
vector<vector<int>> res;
vector<int> tmp;
backtrack(res, tmp, nums, );
return res;
}
void backtrack(vector<vector<int>>& res, vector<int>& tmp, vector<int>& nums, int s) {
res.push_back(tmp);
for (int i = s; i < nums.size(); i++) {
if (i > s && nums[i] == nums[i - ]) {
continue;
} else {
tmp.push_back(nums[i]);
backtrack(res, tmp, nums, i + );
tmp.pop_back();
}
}
}
};
131. Palindrome Partitioning
https://leetcode.com/problems/palindrome-partitioning/description/
Given a string s, partition s such that every substring of the partition is a palindrome. Return all possible palindrome partitioning of s. For example, given s = "aab",
Return [
["aa","b"],
["a","a","b"]
]
先用dp计算任意子串是否为回文,再使用dfs收集合法的partition。
class Solution {
public:
vector<vector<string>> partition(string s) {
int l = s.size();
vector<vector<bool>> dp(l, vector<bool>(l, false));
for (int i = ; i < l; i++) dp[i][i] = true;
for (int len = ; len <= l; len++) {
for (int i = ; i + len - < l; i++) {
int j = i + len - ;
dp[i][j] = s[i] == s[j] && (i + > j - || dp[i + ][j - ]);
}
}
vector<string> path;
vector<vector<string>> res;
dfs(s, path, dp, res, );
return res;
}
void dfs(const string& s, vector<string>& path, vector<vector<bool>>& dp, vector<vector<string>>& res, int start) {
if (start >= s.size()) {
res.push_back(path);
return;
}
for (int i = start; i < s.size(); i++) {
if (dp[start][i]) {
path.push_back(s.substr(start, i - start + ));
dfs(s, path, dp, res, i + );
path.pop_back();
}
}
}
};
132. Palindrome Partitioning II
https://leetcode.com/problems/palindrome-partitioning-ii/description/
Given a string s, partition s such that every substring of the partition is a palindrome. Return the minimum cuts needed for a palindrome partitioning of s. For example, given s = "aab",
Return since the palindrome partitioning ["aa","b"] could be produced using cut.
dfs超时,DP一次AC。partition的DP递推公式和判断回文的递推公式不同,[i,j]不满足回文的时候,不能只考虑[i+1,j]和[i,j-1]令其较小值+1,因为[i+1,j]和[i,j-1]虽然可能组成最长的回文子串,也可能partition次数很多!因此要再用一个minCut数组存储最小的cut.
class Solution {
public:
int minCut(string s) {
int n = s.size();
if (n < ) return ;
vector<vector<bool>> dp(n, vector<bool>(n, false));
vector<int> minCut(n + );
for (int i = ; i <= n; i++) minCut[i] = i - ;
for (int i = ; i < n; i++) dp[i][i] = true;
for (int i = ; i < n; i++) {
for(int j = ; j <= i; j++) {
if (s[i] == s[j] && (j + > i || dp[j + ][i - ])) dp[j][i] = true;
if (dp[j][i]) minCut[i + ] = min( + minCut[j], minCut[i + ]);
}
}
return minCut[n];
}
};
77. Combinations
https://leetcode.com/problems/combinations/description/
Given two integers n and k, return all possible combinations of k numbers out of ... n. For example,
If n = and k = , a solution is: [
[,],
[,],
[,],
[,],
[,],
[,],
]
dfs。
class Solution {
public:
vector<vector<int>> combine(int n, int k) {
vector<vector<int>> res;
vector<int> path;
dfs(res, path, , n, k);
return res;
}
void dfs(vector<vector<int>>& res, vector<int>& path, int start, int n, int k) {
if (path.size() == k) {
res.push_back(path);
return;
}
for (int i = start; i <= n; i++) {
path.push_back(i);
dfs(res, path, i + , n, k);
path.pop_back();
}
}
};
79. Word Search
https://leetcode.com/problems/word-search/description/
Given a 2D board and a word, find if the word exists in the grid. The word can be constructed from letters of sequentially adjacent cell, where "adjacent" cells are those horizontally or vertically neighboring. The same letter cell may not be used more than once. For example,
Given board = [
['A','B','C','E'],
['S','F','C','S'],
['A','D','E','E']
]
word = "ABCCED", -> returns true,
word = "SEE", -> returns true,
word = "ABCB", -> returns false.
dfs。和maze那道题对比,思考想为什么要恢复原状态(回溯),回溯会不会造成死循环?
class Solution {
private:
int m, n;
int bias[] = {, , -, , };
bool exist(vector<vector<char>>& board, string& word, vector<vector<bool>>& visited, int row, int col, int start) {
if (start == word.size() || row < || row >= m || col < || col >= n || word[start] != board[row][col] || visited[row][col]) return false;
if (start + == word.size()) return true;
visited[row][col] = true;
for (int i = ; i < ; i++) {
int p = row + bias[i], q = col + bias[i + ];
if (exist(board, word, visited, p, q, start + )) return true;
}
visited[row][col] = false;
return false;
}
public:
bool exist(vector<vector<char>>& board, string word) {
if (word.size() == ) return true;
m = board.size();
if (m == ) return false;
n = board[].size();
if (n == ) return false;
vector<vector<bool>> visited(m, vector<bool> (n, false));
for (int i = ; i < m; i++) {
for (int j = ; j < n; j++) {
if (exist(board, word, visited, i, j, )) return true;
}
}
return false;
}
};
none-in-place
89. Gray Code
https://leetcode.com/problems/gray-code/description/
The gray code is a binary numeral system where two successive values differ in only one bit. Given a non-negative integer n representing the total number of bits in the code, print the sequence of gray code. A gray code sequence must begin with . For example, given n = , return [,,,]. Its gray code sequence is: -
-
-
-
Note:
For a given n, a gray code sequence is not uniquely defined. For example, [,,,] is also a valid gray code sequence according to the above definition. For now, the judge is able to judge based on one instance of gray code sequence. Sorry about that.
递归。从0开始,不断从起始位或者终止位补0和1(从起始位补的话不必补0,更简洁)。尝试从终止位补0或1出错,不知道为啥。
class Solution {
public:
vector<int> grayCode(int n) {
vector<int> res(, );
for (int i = ; i < n; i++) {
for(int s = res.size() - ; s >= ; s--) res.push_back(res[s] | ( << i));
}
return res;
}
};
211. Add and Search Word - Data structure design
https://leetcode.com/problems/add-and-search-word-data-structure-design/description/
Design a data structure that supports the following two operations: void addWord(word)
bool search(word)
search(word) can search a literal word or a regular expression string containing only letters a-z or .. A . means it can represent any one letter. For example: addWord("bad")
addWord("dad")
addWord("mad")
search("pad") -> false
search("bad") -> true
search(".ad") -> true
search("b..") -> true
Note:
You may assume that all words are consist of lowercase letters a-z.
挺难!一刷调试了4个小时才AC!理解严重不够!多刷!二刷没有AC,对外层for循环和run的更新有了更深的理解。但是对于返回值的判定还是理解不够,再刷!
class TrieNode {
public:
bool isKey;
TrieNode* child[];
TrieNode(): isKey(false) {
memset(child, NULL, sizeof(TrieNode*) * );
}
}; class WordDictionary {
private:
TrieNode* root;
bool find(const char* w, TrieNode* root) {
TrieNode* tmp = root;
for (int i = ; w[i]; i++) {
if (tmp && w[i] != '.') {
tmp = tmp->child[w[i] - 'a'];
} else if (tmp && w[i] == '.') {
TrieNode* run = tmp;
for (int j = ; j < ; j++) {
run = tmp->child[j];
if (find(w + i + , run)) {
return true;
}
}
tmp = run;
} else {
break;
}
}
return tmp && (tmp->isKey);
} public:
/** Initialize your data structure here. */
WordDictionary() {
root = new TrieNode();
} /** Adds a word into the data structure. */
void addWord(string word) {
TrieNode* tmp = root;
for (char c: word) {
if (!tmp->child[c - 'a']) {
tmp->child[c - 'a'] = new TrieNode();
}
tmp = tmp->child[c - 'a'];
}
tmp->isKey = true;
} /** Returns if the word is in the data structure. A word could contain the dot character '.' to represent any one letter. */
bool search(string word) {
return find(word.c_str(), root);
}
}; /**
* Your WordDictionary object will be instantiated and called as such:
* WordDictionary obj = new WordDictionary();
* obj.addWord(word);
* bool param_2 = obj.search(word);
*/
674. Longest Continuous Increasing Subsequence
https://leetcode.com/contest/leetcode-weekly-contest-49/problems/longest-continuous-increasing-subsequence/
Given an unsorted array of integers, find the length of longest continuous increasing subsequence. Example :
Input: [,,,,]
Output:
Explanation: The longest continuous increasing subsequence is [,,], its length is .
Even though [,,,] is also an increasing subsequence, it's not a continuous one where 5 and 7 are separated by 4.
Example :
Input: [,,,,]
Output:
Explanation: The longest continuous increasing subsequence is [], its length is .
Note: Length of the array will not exceed ,.
比较简单,但是这种题我是比较害怕的!还要继续总结!多总结!这才是进步的捷径!
class Solution {
public:
int findLengthOfLCIS(vector<int>& nums) {
if (nums.size() < ) {
return ;
}
int res = INT_MIN, tmp = ;
for (int i = ; i < nums.size(); i++) {
tmp = i == ? : (nums[i] > nums[i - ] ? tmp + : );
res = max(tmp, res);
}
return res;
}
};
673. Number of Longest Increasing Subsequence
https://leetcode.com/problems/number-of-longest-increasing-subsequence/description/
Given an unsorted array of integers, find the number of longest increasing subsequence. Example :
Input: [,,,,]
Output:
Explanation: The two longest increasing subsequence are [, , , ] and [, , , ].
Example :
Input: [,,,,]
Output:
Explanation: The length of longest continuous increasing subsequence is , and there are subsequences' length is 1, so output 5.
Note: Length of the given array will be not exceed and the answer is guaranteed to be fit in -bit signed int.
跟上一题很像!怪不得邓邓把上一道题看成这道题!DP难在算法的理解。看了半天没理解,看了大神的注释之后豁然开朗!一刷AC,但是理解不够,再刷!二刷DEBUG了很久,还是理解不够,心不在焉漏洞百出!再刷!
class Solution {
public:
int findNumberOfLIS(vector<int>& nums) {
int n = nums.size(), max_len = , res = ;
vector<int> len(n, ); // length of LIS ending with nums[i].
vector<int> cnt(n, ); // count of LIS ending with nums[i].
for (int i = ; i < n; i++) {
for (int j = ; j < i; j++) {
if (nums[i] > nums[j]) { // increasing pair
if (len[j]+ > len[i]) { // a longer LIS found, reset the count to the new one
len[i] = len[j] + ;
cnt[i] = cnt[j];
} else if (len[j] + == len[i]) { //another same length, add number of solutions to it
cnt[i] += cnt[j];
}
}
}
max_len = max(max_len, len[i]);
}
for (int i = ; i < n; i++) {
res += (len[i] == max_len ? cnt[i] : );
}
return res;
}
};
676. Implement Magic Dictionary
https://leetcode.com/contest/leetcode-weekly-contest-49/problems/implement-magic-dictionary/
Implement a magic directory with buildDict, and search methods. For the method buildDict, you'll be given a list of non-repetitive words to build a dictionary. For the method search, you'll be given a word, and judge whether if you modify exactly one character into another character in this word, the modified word is in the dictionary you just built. Example :
Input: buildDict(["hello", "leetcode"]), Output: Null
Input: search("hello"), Output: False
Input: search("hhllo"), Output: True
Input: search("hell"), Output: False
Input: search("leetcoded"), Output: False
Note:
You may assume that all the inputs are consist of lowercase letters a-z.
For contest purpose, the test data is rather small by now. You could think about highly efficient algorithm after the contest.
Please remember to RESET your class variables declared in class MagicDictionary, as static/class variables are persisted across multiple test cases. Please see here for more details.
一开始想用set或者vector实现,发现效率太低,就改为用字典树实现,字典树实现太难调试了,再刷要把字典树的算法搞定!之后使用set实现,AC了,但是效率肯定很低。
class MagicDictionary {
private:
unordered_set<string> d;
public:
/** Initialize your data structure here. */
MagicDictionary() { } /** Build a dictionary through a list of words */
void buildDict(vector<string> dict) {
for(string s: dict) {
d.insert(s);
}
} /** Returns if there is any word in the trie that equals to the given word after modifying exactly one character */
bool search(string word) {
int change_times = ;
for (int i = ; i < word.size(); i++) {
for (char c = 'a'; c <= 'z'; c++) {
if (c != word[i]) {
char tmp = word[i];
word[i] = c;
if (d.find(word) != d.end()) {
return true;
}
word[i] = tmp;
}
}
}
return false;
}
}; /**
* Your MagicDictionary object will be instantiated and called as such:
* MagicDictionary obj = new MagicDictionary();
* obj.buildDict(dict);
* bool param_2 = obj.search(word);
*/
class TrieNode {
public:
bool isKey;
TrieNode* child[];
TrieNode(): isKey(false) {
memset(child, NULL, sizeof(TrieNode*) * );
}
}; class MagicDictionary {
private:
TrieNode* root;
bool find(const char* w, TrieNode* run, bool changed) {
for (int i = ; w[i]; i++) {
if ( run && changed) {
run = run->child[w[i] - 'a'];
} else {
if (run && run->child[w[i] - 'a']) {
run = run->child[w[i] - 'a'];
} else if (run && !run->child[w[i] - 'a']) {
TrieNode* tmp = run;
for (int j = ; j < ; j++) {
tmp = run->child[w[i] - 'a'];
if (find(w + i + , tmp, true)) {
return true;
}
}
run = tmp;
} else {
break;
}
}
}
return run && run->isKey;
} public:
/** Initialize your data structure here. */
MagicDictionary() {
root = new TrieNode();
} /** Build a dictionary through a list of words */
void buildDict(vector<string> dict) {
for(string s: dict) {
TrieNode * tmp = root;
for (char c: s) {
if (!tmp->child[c -'a']) {
tmp->child[c - 'a'] = new TrieNode();
}
tmp = tmp->child[c - 'a'];
}
}
} /** Returns if there is any word in the trie that equals to the given word after modifying exactly one character */
bool search(string word) {
return find(word.c_str(), root, false);
}
}; /**
* Your MagicDictionary object will be instantiated and called as such:
* MagicDictionary obj = new MagicDictionary();
* obj.buildDict(dict);
* bool param_2 = obj.search(word);
*/
没AC的字典树
675. Cut Off Trees for Golf Event
https://leetcode.com/contest/leetcode-weekly-contest-49/problems/cut-off-trees-for-golf-event/
You are asked to cut off trees in a forest for a golf event. The forest is represented as a non-negative 2D map, in this map: represents the obstacle can't be reached.
represents the ground can be walked through.
The place with number bigger than represents a tree can be walked through, and this positive number represents the tree's height.
You are asked to cut off all the trees in this forest in the order of tree's height - always cut off the tree with lowest height first. And after cutting, the original place has the tree will become a grass (value 1). You will start from the point (, ) and you should output the minimum steps you need to walk to cut off all the trees. If you can't cut off all the trees, output -1 in that situation. You are guaranteed that no two trees have the same height and there is at least one tree needs to be cut off. Example :
Input:
[
[,,],
[,,],
[,,]
]
Output:
Example :
Input:
[
[,,],
[,,],
[,,]
]
Output: -
Example :
Input:
[
[,,],
[,,],
[,,]
]
Output:
Explanation: You started from the point (,) and you can cut off the tree in (,) directly without walking.
Hint: size of the given matrix will not exceed 50x50.
不太难的一道BFS的题目,但是非常繁琐!DEBUG了非常长的时间!对于树而言BFS就是层序遍历,DFS就是后续遍历!代码我到最后都不知道为什么AC了!这份代码非常经典,要拿出来再刷,再总结!
class Solution {
private:
struct TreeComparator {
bool operator() (vector<int> a, vector<int> b) {
return a[] > b[];
}
}; int bfs(vector<vector<int> > forest, int i0, int j0, int i1, int j1) {
if (i0 == i1 && j0 == j1) {
return ;
}
int m = forest.size(), n = forest[].size();
int delta[][] = {-, , , , , -, , };
queue<pair<int, int> > q;
q.push({i0, j0}); forest[i0][j0] = -forest[i0][j0];
int dis = ;
while (!q.empty()) {
dis++;
for (int k = q.size(); k > ; k--) {
pair<int, int> p = q.front();
q.pop();
for (int d = ; d < ; d++) {
int i = p.first + delta[d][], j = p.second + delta[d][];
if (i == i1 && j == j1) {
return dis;
}
if (i < || i >= m || j < || j >= n || forest[i][j] <= ) {
continue;
}
forest[i][j] = -forest[i][j];
q.push({i, j});
}
}
}
return -;
} public:
int cutOffTree(vector<vector<int>>& forest) {
priority_queue<vector<int>, vector<vector<int> >, TreeComparator> trees;
int m = forest.size(), n = forest[].size();
for (int i = ; i < m; i++) {
for (int j = ; j < n; j++) {
if (forest[i][j] > ) {
trees.push({i, j, forest[i][j]});
}
}
}
int total = ; for (int i = , j = , i1 = , j1 = ; !trees.empty(); i = i1, j = j1) {
vector<int> tree = trees.top();
trees.pop();
i1 = tree[];
j1= tree[];
int dis = bfs(forest, i, j, i1, j1);
if (dis == -) {
return -;
}
total += dis;
}
return total;
} };
198. House Robber
https://leetcode.com/problems/house-robber/description/
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.
比较简单,DP一刷AC。时间复杂度和空间复杂度都是O(N),可以将空间复杂度降至O(1)。二刷使用时间复杂度O(N),空间复杂度为O(1)的DP算法,一次AC。
class Solution {
public:
int rob(vector<int>& nums) {
int n = nums.size();
if (n < ) {
return ;
} else if (n < ) {
return nums[];
}
vector<int> r(n, );
r[] = nums[];
r[] = max(nums[], nums[]);
for (int i = ; i < n; i++) {
r[i] = max(r[i - ], r[i - ] + nums[i]);
}
return r[n - ];
}
};
class Solution {
public:
int rob(vector<int>& nums) {
int n = nums.size();
if (n < ) {
return ;
} else if (n < ) {
return nums[];
}
int e = , i = ;
for (int x : nums) {
int e1 = e, i1 = i;
i = e1 + x;
e = max(i1, e1);
}
return max(i, e);
}
};
O(1)-DP
213. House Robber II
https://leetcode.com/problems/house-robber-ii/description/
Note: This is an extension of House Robber. After robbing those houses on that street, the thief has found himself a new place for his thievery so that he will not get too much attention. This time, all houses at this place are arranged in a circle. That means the first house is the neighbor of the last one. Meanwhile, the security system for these houses remain the same as for those in the previous street. 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.
一刷没思路,使用大神的DP思路没有对nums的长度为1时的场景进行判断,WA。关键是将该题转化到上面一题。再刷的时候注意理解,思考留出一个house不rob从而破环的合理性。
class Solution {
private:
int rob(vector<int>& nums, int s, int e) {
int i = , j = ;
for (int k = s; k <= e; k++) {
int i1 = i, j1 = j;
i = j1 + nums[k];
j = max(i1, j1);
}
return max(i, j);
}
public:
int rob(vector<int>& nums) {
if (nums.size() == ) {
return nums[];
}
return max(rob(nums, , nums.size() - ), rob(nums, , nums.size() - ));
}
};
dp
96. Unique Binary Search Trees
https://leetcode.com/problems/unique-binary-search-trees/description/
Given n, how many structurally unique BST's (binary search trees) that store values 1...n? For example,
Given n = , there are a total of unique BST's. \ / / / \ \ / / \ \
DP思路:将1到n分别作为根,左右两侧都是一个规模更小的子问题,左右两侧结果相乘就是一种情况,枚举所有情况求和即可。一刷AC,二刷没AC,思路不熟。三刷思路忘记了,看了一遍注释AC。四刷使用数组没有初始化WA,应该使用vector。这道题和矩阵相乘的那道题很类似,都是从序列中间取一个元素,分割序列将问题转化为规模更小的子问题,同时分割元素可以是序列中的任意一个元素,这类的递推函数很常见。DP问题的解不仅可以由一个小规模子问题的解得到,还可以由多个甚至所有小规模子问题的解的组合得到。
/**
* Taking 1~n as root respectively:
* 1 as root: # of trees = F(0) * F(n-1) // F(0) == 1
* 2 as root: # of trees = F(1) * F(n-2)
* 3 as root: # of trees = F(2) * F(n-3)
* ...
* n-1 as root: # of trees = F(n-2) * F(1)
* n as root: # of trees = F(n-1) * F(0)
*
* So, the formulation is:
* F(n) = F(0) * F(n-1) + F(1) * F(n-2) + F(2) * F(n-3) + ... + F(n-2) * F(1) + F(n-1) * F(0)
*/
class Solution {
public:
int numTrees(int n) {
int dp[n + ];
dp[] = , dp[] = ;
for (int i = ; i < n + ; i++) {
dp[i] = ;
for (int j = ; j <= i; j++) {
dp[i] += dp[j - ] * dp[i - j];
}
}
return dp[n];
}
};
public class MatrixMultiplication {
public static void main(String[] args) {
int[] p = {2, 4, 5, 4};
System.out.println(matrixChain(p));
} public static int matrixChain(int[] p) {
int n = p.length;
int[][] dp = new int[n][n];
for (int i = 1; i < n - 1; i++) {
dp[i][i + 1] = p[i - 1] * p[i] * p[i + 1];
}
for (int i = 1; i < n; i++) {
for (int j = i + 2; j < n; j++) {
for (int k = i; k < j; k++) {
int tmp = dp[i][k] + dp[k + 1][j] + p[i - 1] * p[k] * p[j];
dp[i][j] = (dp[i][j] == 0 ? tmp : Math.min(dp[i][j], tmp));
}
}
}
return dp[1][n - 1];
}
}
matrix multiplication
95. Unique Binary Search Trees II
https://leetcode.com/problems/unique-binary-search-trees-ii/description/
Given an integer n, generate all structurally unique BST's (binary search trees) that store values 1...n. For example,
Given n = , your program should return all unique BST's shown below. \ / / / \ \ / / \ \
BFS或递归。BFS从1到n,逐渐扩充res,然后遍历上一个节点加入后的res列表,在每棵树上添加新的节点(每个可能的右子树),时间复杂度O(N^2logN)~O(N^3logN)。递归将问题转化为区间的BST生成,遍历范围,选取元素为根,2个子问题分别生成所有左子树left与所有右子树right,然后按照96的思路将所有左右子树的组合得到就是结果。
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
vector<TreeNode*> generateTrees(int n) {
vector<TreeNode *> res(, NULL);
for (int i = ; i <= n; i++) {
int len = res.size();
for (int j = ; j < len; j++) {
auto head = res[j], cur = head;
while (head) {
if (head->right) {
auto tmp = head->right; head->right = new TreeNode(i);
head->right->left = tmp;
res.push_back(copy(res[j]));
head->right = head->right->left;
} else {
head->right = new TreeNode(i);
res.push_back(copy(res[j]));
head->right = NULL;
}
head = head->right;
}
TreeNode * tmp = new TreeNode(i);
tmp->left = res[j]; res[j] = tmp;
}
}
return res.size() == && res[] == NULL ? vector<TreeNode*>() : res;
}
TreeNode * copy(TreeNode *root) {
if (!root) return NULL;
TreeNode *new_root = new TreeNode(root->val);
new_root->left = copy(root->left);
new_root->right = copy(root->right);
return new_root;
}
};
bfs
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
vector<TreeNode*> generateTrees(int n) {
if (n == ) return vector<TreeNode*> ();
return dfs(, n);
}
vector<TreeNode*> dfs(int b, int e) {
if (b > e) return vector<TreeNode*> (, NULL);
vector<TreeNode*> res;
for (int i = b; i <= e; i++) {
auto left = dfs(b, i - ), right = dfs(i + , e);
for (auto l_node : left) {
for (auto r_node : right) {
TreeNode *root = new TreeNode(i);
root->left = l_node; root->right = r_node;
res.push_back(root);
}
}
}
return res;
}
};
recursion
647. Palindromic Substrings
https://leetcode.com/problems/palindromic-substrings/description/
Given a string, your task is to count how many palindromic substrings in this string. The substrings with different start indexes or end indexes are counted as different substrings even they consist of same characters. Example :
Input: "abc"
Output:
Explanation: Three palindromic strings: "a", "b", "c".
Example :
Input: "aaa"
Output:
Explanation: Six palindromic strings: "a", "a", "a", "aa", "aa", "aaa".
一刷使用DP算法AC,时间复杂度和空间复杂度都是O(N^2)。讨论区应该有更好的解法,再刷尝试!讨论区有一个经典的解决字符串中回文子串类问题的算法叫“曼彻斯特算法”,时间复杂度是O(N)。要对这种类型的题目和这个经典算法进行总结!
class Solution {
public:
int countSubstrings(string s) {
int n = s.size();
if (n < ) {
return ;
} else if (n == ) {
return ;
}
vector<int> row(n, );
vector<vector<int> > dp(n, row);
// memset(dp, 0, sizeof(int));
for (int i = ; i < n; i++) {
dp[i][i] = ;
}
for (int i = ; i < n; i++) {
for (int j = ; j <= i; j++) {
if (s[] == s[j]) {
if (j > && dp[][j - ]) {
dp[][j] = ;
}
if (j < ) {
dp[][j] = ;
}
}
}
for (int j = ; j <= i; j++) {
if (s[j] == s[i]) {
if (i - > j && dp[j + ][i - ]) {
dp[j][i] = ;
}
if (i - j < ) {
dp[j][i] = ;
}
}
}
}
int res = ;
for (int i = ; i < n; i++) {
for (int j = i; j < n; j++) {
res += dp[i][j];
}
}
return res;
}
};
416. Partition Equal Subset Sum
https://leetcode.com/problems/partition-equal-subset-sum/description/
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 .
The array size will not exceed .
Example : Input: [, , , ] Output: true Explanation: The array can be partitioned as [, , ] and [].
Example : Input: [, , , ] Output: false Explanation: The array cannot be partitioned into equal sum subsets.
一刷没AC,使用时间复杂度为O(N!)的backtracing算法,出现很多CE!最后TLE。也有人说时间复杂度为O(pow(2, N))的!
class Solution {
private:
bool backtrack(vector<int>& nums, int s, int t) {
if (t <= ) {
return t==;
}
for (int i = s; i < nums.size(); i++) {
if (backtrack(nums, i+, t - nums[i])) {
return true;
}
}
return false;
}
public:
bool canPartition(vector<int>& nums) {
long long sum = accumulate(nums.begin(), nums.end(), );
return (!(sum % )) && backtrack(nums, , sum >> );
}
};
backtracing
这是个典型的0/1背包问题,0/1背包问题的特点是从一组数中选取某些数达到一定的值。对0/1背包问题的一个很好的解释在下面的链接中:
https://discuss.leetcode.com/topic/67539/0-1-knapsack-detailed-explanation
这一题使用的DP解法对标准0/1背包算法进行了优化,因为题目不需要知道更多的信息,数组开一维就可以。
class Solution {
public:
bool canPartition(vector<int>& nums) {
long long sum = accumulate(nums.begin(), nums.end(), );
if (sum % ) {
return false;
}
long long target = sum >> ;
vector<bool> dp(target + , false);
dp[] = true;
for (int num: nums) {
for (long long i = target; i >= num; i--) {
dp[i] = dp[i] || dp[i - num];
}
}
return dp[target];
}
};
dp_1d
数组开二维也可以,但是比较麻烦,需要更多的初始化,操作!
class Solution {
public:
bool canPartition(vector<int>& nums) {
long long sum = accumulate(nums.begin(), nums.end(), );
if (sum % ) {
return false;
}
long long target = sum >> ;
int n = nums.size();
vector<bool> row(target + , false);
vector<vector<bool>> dp(n+, row);
for (int i = ; i <= n; i++) {
dp[i][] = true;
}
for (int k = ; k < n + ; k++) {
for (long long i = target; i >= nums[k - ]; i--) {
dp[k][i] = dp[k-][i];
dp[k][i] = dp[k][i] || dp[k -][i - nums[k - ]];
}
}
return dp[n][target];
}
};
最优化方法是使用bitset的方法,时间复杂度为O(N),空间复杂度为O(1)!
class Solution {
public:
bool canPartition(vector<int>& nums) {
long long sum = accumulate(nums.begin(), nums.end(), );
if (sum % ) {
return false;
}
long long target = sum >> ;
bitset<> bits();
for (auto n: nums) {
bits |= (bits << n);
}
return bits[target];
}
};
bitset
非常经典,再刷,把上面三种方法都理解透!
139. Word Break
https://leetcode.com/problems/word-break/description/
Given a non-empty string s and a dictionary wordDict containing a list of non-empty words, determine if s can be segmented into a space-separated sequence of one or more dictionary words. You may assume the dictionary does not contain duplicate words. For example, given
s = "leetcode",
dict = ["leet", "code"]. Return true because "leetcode" can be segmented as "leet code".
DP。将s[0, j]分成两部分s[0, i]和s[i+1, j],如果s[i+1, j]在字典中,s[0,i]可以由词典中的词拼成,则s[0, j]也可以由字典中的词拼成。注意dp[0]=true的初始化。dp[0]对结果没有意义,但是在dp更新时有用。
class Solution {
public:
bool wordBreak(string s, vector<string>& wordDict) {
int ss = s.size();
unordered_set<string> dict;
for (string word : wordDict) dict.insert(word);
vector<bool> dp(ss + , false);
dp[] = true;
for (int j = ; j <= ss; j++) {
for (int i = j - ; i >= ; i--) {
dp[j] = dp[i] && dict.find(s.substr(i, j - i)) != dict.end();
if (dp[j]) break;
}
}
return dp[ss];
}
};
dp
140. Word Break II
https://leetcode.com/problems/word-break-ii/description/
Given a non-empty string s and a dictionary wordDict containing a list of non-empty words, add spaces in s to construct a sentence where each word is a valid dictionary word. You may assume the dictionary does not contain duplicate words. Return all such possible sentences. For example, given
s = "catsanddog",
dict = ["cat", "cats", "and", "sand", "dog"]. A solution is ["cats and dog", "cat sand dog"]. UPDATE (//):
The wordDict parameter had been changed to a list of strings (instead of a set of strings). Please reload the code definition to get the latest changes.
和上题的思路相同,但是使用的是递归+MEMO,因为要把所有可能的结果都保存下来。
f(s[0, j]) = f(s[0, i]) + word(s[i + 1, j])
class Solution {
public:
vector<string> wordBreak(string s, vector<string>& wordDict) {
string path = "";
vector<string> res;
unordered_set<string> dict;
int max_len = ;
for (string word : wordDict) {
dict.insert(word); max_len = max(max_len, (int)word.size());
}
dfs(s, dict, , path, max_len, res);
return res;
} void dfs(string &s, const unordered_set<string> &dict, int start, string &path, const int &max_len, vector<string> &res) {
if (start >= s.size()) {
if (path.size() > && path.back() == ' ') res.push_back(path.substr(, path.size() - ));
return;
}
for (int i = ; i < max_len; i++) {
if (start + i >= s.size()) break;
string tmp = s.substr(start, i + );
if (dict.find(tmp) != dict.end()) {
path += (tmp + " ");
dfs(s, dict, start + i + , path, max_len, res);
path.resize(path.size() - i - );
}
}
}
};
dfs_TLE
class Solution {
private:
unordered_map<string, vector<string>> mem;
public:
vector<string> wordBreak(string s, vector<string>& wordDict) {
if (mem.find(s) != mem.end()) return mem[s];
vector<string> res;
if (find(wordDict.begin(), wordDict.end(), s) != wordDict.end()) res.push_back(s); // s本身就是dict中的一个元素
for (int i = ; i < s.size(); i++) {
string word = s.substr(i);
if (find(wordDict.begin(), wordDict.end(), word) != wordDict.end()) {
// 尾部的word合法, 开始递归
// f([0, j]) = f([0, i]) + word(i + 1, j)
// 递推表达式同139的DP方法.
vector<string> pre = wordBreak(s.substr(, i), wordDict);
for (auto &s : pre) s += " " + word;
res.insert(res.begin(), pre.begin(), pre.end()); // 将递归得到的结果添加到结果列表中
}
}
mem[s] = res;
return res;
}
};
recursion+memo
135. Candy
There are N children standing in a line. Each child is assigned a rating value. You are giving candies to these children subjected to the following requirements: Each child must have at least one candy.
Children with a higher rating get more candies than their neighbors.
What is the minimum candies you must give?
BFS或DP。BFS算法将问题转化为拓扑排序,O(N^2)的复杂度,超时。一维DP先从左向右扫描数组,与左侧元素比较更新DP,之后反向扫描数组,根据元素与右侧元素的关系修改DP。可以将空间复杂度降到O(1),同时保留O(N)的时间复杂度。
class Solution {
public:
int candy(vector<int>& ratings) {
map<int, set<int>> g;
for (int i = ; i < ratings.size(); i++) {
g[i] = set<int>();
if (i > && ratings[i] > ratings[i - ]) g[i].insert(i - );
if (i + < ratings.size() && ratings[i] > ratings[i + ]) g[i].insert(i + );
}
vector<int> q, next;
int layer = , res = ;
for (auto iter = g.begin(); iter != g.end(); iter++) {
if (iter->second.empty()) q.push_back(iter->first);
}
while (!q.empty()) {
next.clear();
for (int cur : q) g.erase(cur);
res += layer * q.size();
for (int cur : q) {
for (auto iter = g.begin(); iter != g.end(); iter++) {
if (iter->second.find(cur) != iter->second.end()) {
iter->second.erase(cur);
if (iter->second.empty()) next.push_back(iter->first);
}
}
}
swap(q, next); layer++;
}
return res;
}
};
bfs-tle
class Solution {
public:
int candy(vector<int>& ratings) {
int len = ratings.size(), res = ;
vector<int> dp(len, );
for (int i = ; i < len; i++) {
if (ratings[i] > ratings[i - ]) dp[i] += dp[i - ];
}
res += len > ? dp.back() : ;
for (int i = len - ; i >= ; i--) {
if (ratings[i] > ratings[i + ] && dp[i] <= dp[i + ]) dp[i] = dp[i + ] + ;
res += dp[i];
}
return res;
}
};
dp
464. Can I Win
https://leetcode.com/problems/can-i-win/description/
In the "100 game," two players take turns adding, to a running total, any integer from ... The player who first causes the running total to reach or exceed wins. What if we change the game so that players cannot re-use integers? For example, two players might take turns drawing from a common pool of numbers of .. without replacement until they reach a total >= . Given an integer maxChoosableInteger and another integer desiredTotal, determine if the first player to move can force a win, assuming both players play optimally. You can always assume that maxChoosableInteger will not be larger than and desiredTotal will not be larger than . Example Input:
maxChoosableInteger =
desiredTotal = Output:
false Explanation:
No matter which integer the first player choose, the first player will lose.
The first player can choose an integer from up to .
If the first player choose , the second player can only choose integers from up to .
The second player will win by choosing and get a total = , which is >= desiredTotal.
Same with other integers chosen by the first player, the second player will always win.
自自己没思路,大神思路不太理解。时间复杂度为(dfs导致递归,时间复杂度不会分析),空间复杂度为O(2^N)。一刷dfs的循环次数写错WA。再刷!
class Solution {
private:
int m[ << ] = {};
bool dfs(int M, int T, int k) {
if (T <= || m[k]) {
return T > && m[k] > ;
}
for (int i = ; i < M; i++) {
if (!(k & << i) && !dfs(M, T - i - , k | << i)) {
return m[k] = ;
}
}
return !(m[k] = -);
}
public:
bool canIWin(int maxChoosableInteger, int desiredTotal) {
int M = maxChoosableInteger, T = desiredTotal;
int sum = (M + ) * M / ;
return T < ? true : sum < T ? false : sum == T ? M % : dfs(M, T, );
}
};
467. Unique Substrings in Wraparound String
https://leetcode.com/problems/unique-substrings-in-wraparound-string/description/
Consider the string s to be the infinite wraparound string of "abcdefghijklmnopqrstuvwxyz", so s will look like this: "...zabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcd....". Now we have another string p. Your job is to find out how many unique non-empty substrings of p are present in s. In particular, your input is the string p and you need to output the number of different non-empty substrings of p in the string s. Note: p consists of only lowercase English letters and the size of p might be over . Example :
Input: "a"
Output: Explanation: Only the substring "a" of string "a" is in the string s.
Example :
Input: "cac"
Output:
Explanation: There are two substrings "a", "c" of string "cac" in the string s.
Example :
Input: "zab"
Output:
Explanation: There are six substrings "z", "a", "b", "za", "ab", "zab" of string "zab" in the string s.
大神思路理解不透彻,有隐患!时间复杂度O(N),空间复杂度O(1)。一刷理解大神思路的基础上自己实现一次AC。再刷一次!但是这个解法真的是DP吗?
class Solution {
public:
int findSubstringInWraproundString(string p) {
vector<int> dp(, );
int n = p.size(), curLen = ;
for (int i = ; i < n; i++) {
if (i > && (p[i] - p[i - ] == || p[i - ] - p[i] == )) {
curLen ++;
} else {
curLen = ;
}
dp[p[i] - 'a'] = max(dp[p[i] - 'a'], curLen);
}
return accumulate(dp.begin(), dp.end(), );
}
};
97. Interleaving String
https://leetcode.com/problems/interleaving-string/description/
Given s1, s2, s3, find whether s3 is formed by the interleaving of s1 and s2. For example,
Given:
s1 = "aabcc",
s2 = "dbbca", When s3 = "aadbbcbcac", return true.
When s3 = "aadbbbaccc", return false.
DP一次AC。二维填表,逐行填充,母问题可以转化为两个子问题。dp[i][j]表示s1的前i个字符和s2的前j个字符是否可以按照题目规定的方式组合成s3的前i+j个字符。
class Solution {
public:
bool isInterleave(string s1, string s2, string s3) {
int l1 = s1.size(), l2 = s2.size(), l3 = s3.size();
if (l1 + l2 != l3) return false;
vector<vector<bool>> dp(l1 + , vector<bool>(l2 + , false));
for (int i = ; i <= l1; i++) {
if (s1.substr(, i) == s3.substr(, i)) dp[i][] = true;
}
for (int j = ; j <= l2; j++) {
if (s2.substr(, j) == s3.substr(, j)) dp[][j] = true;
}
for (int i = ; i <= l1; i++) {
for (int j = ; j <= l2; j++) {
if (dp[i - ][j] && s1[i - ] == s3[i + j - ]) dp[i][j] = true;
if (dp[i][j - ] && s2[j - ] == s3[i + j - ]) dp[i][j] = true;
}
}
return dp[l1][l2];
}
};
221. Maximal Square
https://leetcode.com/problems/maximal-square/description/
Given a 2D binary matrix filled with 's and 1's, find the largest square containing only 's and return its area. For example, given the following matrix: Return .
一刷AC,自己的思路和大神的思路相似,我的思路不够简洁,大神使用square的边长表示square。二刷初始化参数写错,RE。
状态方程的理解:(i, j)是square,则(i-1, j-1), (i-1, j),(i, j-1)必定是size的square!如果三者的size不同,则(i, j)取三者最小的加1。时间复杂度和空间复杂度都是O(M*N)。
class Solution {
public:
int maximalSquare(vector<vector<char>>& matrix) {
int n = matrix.size();
if (n < ) {
return ;
}
int m = matrix[].size();
vector< vector<int> > dp(n, vector<int>(m, ));
int res = ;
for (int i = ; i < n; i++) {
dp[i][] = matrix[i][] - '';
res = max(res, dp[i][]);
}
for (int j = ; j < m; j++) {
dp[][j] = matrix[][j] - '';
res = max(res, dp[][j]);
}
for (int i = ; i < n; i++) {
for (int j = ; j < m; j++) {
if (matrix[i][j] == '') {
dp[i][j] = min(dp[i - ][j - ], min(dp[i - ][j], dp[i][j - ])) + ;
res = max(res, dp[i][j]);
}
}
}
return res * res;
}
};
576. Out of Boundary Paths
https://leetcode.com/problems/out-of-boundary-paths/description/
There is an m by n grid with a ball. Given the start coordinate (i,j) of the ball, you can move the ball to adjacent cell or cross the grid boundary in four directions (up, down, left, right). However, you can at most move N times. Find out the number of paths to move the ball out of grid boundary. The answer may be very large, return it after mod + . Example :
Input:m = , n = , N = , i = , j =
Output:
Explanation: Example :
Input:m = , n = , N = , i = , j =
Output:
Explanation: Note:
Once you move the ball out of boundary, you cannot move it back.
The length and height of the grid is in range [,].
N is in range [,].
一刷按照自己的思路初始时没判断参数有可能的异常,RE。思路正确,效率不高,时间复杂度和空间复杂度均为O(N*n*m)。再刷!二刷使用大神的高效解法。
class Solution {
public:
int findPaths(int m, int n, int N, int i, int j) {
if (N < ) {
return ;
}
vector< vector< vector<int> > > dp(N, vector< vector<int> > (m, vector<int> (n, )));
for (int l = ; l < N; l++) {
for (int k = ; k < m; k++) {
dp[l][k][]++;
dp[l][k][n - ]++;
}
for (int k = ; k < n; k++) {
dp[l][][k]++;
dp[l][m - ][k]++;
}
}
int pBias[] = {, -, , };
int qBias[] = {, , , -};
for (int k = ; k < N; k++) {
for (int p = ; p < m; p++) {
for (int q = ; q < n; q++) {
for (int b = ; b < ; b++) {
int newP = p + pBias[b], newQ = q + qBias[b];
if (newP < m && newP >= && newQ >= && newQ < n) {
dp[k][p][q] += (dp[k - ][newP][newQ] % );
dp[k][p][q] %= ;
}
}
}
}
}
return dp[N - ][i][j];
}
};
650. 2 Keys Keyboard
https://leetcode.com/problems/2-keys-keyboard/description/
Initially on a notepad only one character 'A' is present. You can perform two operations on this notepad for each step: Copy All: You can copy all the characters present on the notepad (partial copy is not allowed).
Paste: You can paste the characters which are copied last time.
Given a number n. You have to get exactly n 'A' on the notepad by performing the minimum number of steps permitted. Output the minimum number of steps to get n 'A'. Example :
Input:
Output:
Explanation:
Intitally, we have one character 'A'.
In step , we use Copy All operation.
In step , we use Paste operation to get 'AA'.
In step , we use Paste operation to get 'AAA'.
Note:
The n will be in the range [, ].
一刷没思路,使用大神的思路AC。大神没有用DP,时间复杂度最好为O(logN),最差O(N),比DP算法效率高,但是比较难以理解。再刷,注意理解!
class Solution {
public:
int minSteps(int n) {
int res = ;
for (int d = ; d <= n; d++) {
while (n % d == ) {
res += d;
n /= d;
}
}
return res;
}
};
377. Combination Sum IV
https://leetcode.com/problems/combination-sum-iv/description/
Given an integer array with all positive numbers and no duplicates, find the number of possible combinations that add up to a positive integer target. Example: nums = [, , ]
target = The possible combination ways are:
(, , , )
(, , )
(, , )
(, )
(, , )
(, )
(, ) Note that different sequences are counted as different combinations. Therefore the output is .
Follow up:
What if negative numbers are allowed in the given array?
How does it change the problem?
What limitation we need to add to the question to allow negative numbers?
一刷没思路,DFS都忘了。大神的top-down的DFS超时,加入memo实现DP后,AC。这个题很经典,和之前整理的回溯法有强关联!注意理解DP的含义,我现在仍然不知道这样做是不是就叫做DP。再刷!注意整理!
class Solution {
private:
vector<int> dp;
int helper(const vector<int>& nums, int target) {
if (dp[target] >= ) {
return dp[target];
}
int res = ;
for (int n : nums) {
if (target >= n) {
res += helper(nums, target - n);
}
}
dp[target] = res;
return res;
}
public:
int combinationSum4(vector<int>& nums, int target) {
dp.resize(target + , -);
dp[] = ;
helper(nums, target);
return dp[target];
}
};
除了上一种top-down的DP方法,还有一种bottom-up的DP方法,这种方法在我看来更像DP。一刷dp空间分配不够,RE。错误在本地没复现,猜测是因为本地使用伙伴内存管理,dp配额有冗余,而网页后端对内存的检测更严格。
class Solution {
public:
int combinationSum4(vector<int>& nums, int target) {
vector<int> dp(target + , );
dp[] = ;
for (int i = ; i <= target; i++) {
for (int n : nums) {
if (i - n >= ) {
dp[i] += dp[i - n];
}
}
}
return dp[target];
}
};
两种方法的空间复杂度都是O(N),时间复杂度均为O(MN),top-down方法虽然使用递归,但是这个时间复杂度容易分析。
376. Wiggle Subsequence
https://leetcode.com/problems/wiggle-subsequence/description/
A sequence of numbers is called a wiggle sequence if the differences between successive numbers strictly alternate between positive and negative. The first difference (if one exists) may be either positive or negative. A sequence with fewer than two elements is trivially a wiggle sequence. For example, [,,,,,] is a wiggle sequence because the differences (,-,,-,) are alternately positive and negative. In contrast, [,,,,] and [,,,,] are not wiggle sequences, the first because its first two differences are positive and the second because its last difference is zero. Given a sequence of integers, return the length of the longest subsequence that is a wiggle sequence. A subsequence is obtained by deleting some number of elements (eventually, also zero) from the original sequence, leaving the remaining elements in their original order. Examples:
Input: [,,,,,]
Output:
The entire sequence is a wiggle sequence. Input: [,,,,,,,,,]
Output:
There are several subsequences that achieve this length. One is [,,,,,,]. Input: [,,,,,,,,]
Output:
Follow up:
Can you do it in O(n) time?
一刷没思路,大神解法集中在贪心和DP两类。贪心算法一刷AC,不好理解。代码还有较大优化空间。意思是每次选山峰的最高点和最低点,为什么这样就可以保证序列最长?
class Solution {
public:
int wiggleMaxLength(vector<int>& nums) {
int n = nums.size();
if (n < ) {
return n;
}
bool allEqual = true;
int i = ;
for (; i < n; i++) {
if (nums[i] != nums[i - ]) {
allEqual = false;
break;
}
}
if (allEqual) {
return ;
}
bool requireBig = nums[i] < nums[];
vector<int> series(, nums[]);
series[] = nums[i];
for (i++; i < n; i++) {
if (requireBig) {
if (series.back() < nums[i]) {
series.push_back(nums[i]);
requireBig = false;
} else if (series.back() > nums[i]) {
series[series.size() - ] = nums[i];
}
} else {
if (series.back() > nums[i]) {
series.push_back(nums[i]);
requireBig = true;
} else if (series.back() < nums[i]) {
series[series.size() - ] = nums[i];
}
}
}
return series.size();
}
};
greedy
DP算法一刷初始化变量名写错,WA。再刷!
class Solution {
public:
int wiggleMaxLength(vector<int>& nums) {
int n = nums.size();
if (n < ) {
return n;
}
vector<int> up(n, );
vector<int> down(n, );
up[] = ;
down[] = ;
for (int i = ; i < n; i++) {
if (nums[i] > nums[i - ]) {
up[i] = down[i - ] + ;
down[i] = down[i - ];
} else if (nums[i] < nums[i - ]) {
down[i] = up[i - ] + ;
up[i] = up[ i - ];
} else {
up[i] = up[i - ];
down[i] = down[i - ];
}
}
return max(up[n - ], down[n - ]);
}
};
dp
两种算法的区别和联系是什么?
516. Longest Palindromic Subsequence
https://leetcode.com/problems/longest-palindromic-subsequence/description/
Given a string s, find the longest palindromic subsequence's length in s. You may assume that the maximum length of s is 1000. Example :
Input: "bbbab"
Output: One possible longest palindromic subsequence is "bbbb".
Example :
Input: "cbbd"
Output: One possible longest palindromic subsequence is "bb".
一刷没思路,大神总结了从暴力递归到简化版DP的四种方法,一刷使用暴力递归发现TLE。二刷使用带memo的递归,由于递归深度与字符串长度相同,字符串过长导致栈空间溢出得到MLE。三刷使用DP,一次AC。空间复杂度为O(N^2),时间复杂度为O(N^2)。四刷使用更高效的DP,一次AC,时间复杂度为O(N^2),空间复杂度为O(N)。不用再刷,但是可以回顾,这个题目很经典。
class Solution {
private:
int helper(int l, int r, string s) {
if (l == r) {
return ;
} else if (l > r) {
return ;
}
return s[l] == s[r] ? + helper(l + , r - , s) : max(helper(l + , r, s), helper(l, r - , s));
}
public:
int longestPalindromeSubseq(string s) {
return helper(, s.size() - , s);
}
};
brute force
class Solution {
private:
int helper(int l, int r, string s, vector< vector<int> >& m) {
if (l == r) {
return ;
} else if (l > r) {
return ;
}
if (m[l][r]) return m[l][r];
return m[l][r] = s[l] == s[r] ? + helper(l + , r - , s, m) : max(helper(l + , r, s, m), helper(l, r - , s, m));
}
public:
int longestPalindromeSubseq(string s) {
int n = s.size();
vector< vector<int> > m(n, vector<int> (n, ));
return helper(, s.size() - , s, m);
}
};
recursion-with-memo
class Solution {
public:
int longestPalindromeSubseq(string s) {
int n = s.size();
vector< vector<int> > dp(n + , vector<int> (n , ));
for (int i = ; i < n; i++) {
dp[][i] = ;
}
for (int i = ; i < n + ; i++) {
for (int j = ; j < n - i + ; j++) {
dp[i][j] = s[j] == s[j + i - ] ? + dp[i - ][j + ] : max(dp[i - ][j], dp[i - ][j + ]);
}
}
return dp[n][];
}
};
class Solution {
public:
int longestPalindromeSubseq(string s) {
int n = s.size();
vector<int> v_2(n, ), v_1(n, ), v(n, ), *p_2 = &v_2, *p_1 = &v_1, *p = &v;
for (int i = ; i < n + ; i++) {
for (int j = ; j < n - i + ; j++) {
p->at(j) = s[j] == s[j + i - ] ? + p_2->at(j + ) : max(p_1->at(j), p_1->at(j + ));
}
swap(p_2, p_1);
swap(p_1, p);
}
return p_1->at();
}
};
efficient dp
暴力递归导致重复计算,于是有了带memo的递归。而随着递归深度增大,栈空间消耗过大,于是有了DP。递归是top-down的思路,而DP则是bottom-up的思路。这道题的关键的状态方程不易理解,需要举个例子,如“bbbab”, 状态方程为("bbbab") = 'b' == 'b' ? 2 + ("bba") ? max("bbba", "bbab")。可以清楚看到"bba"三者都有,而后面两个最大只是("bba") + 1。
322. Coin Change
https://leetcode.com/problems/coin-change/description/
You are given coins of different denominations and a total amount of money amount. Write a function to compute the fewest number of coins that you need to make up that amount. If that amount of money cannot be made up by any combination of the coins, return -. Example :
coins = [, , ], amount =
return ( = + + ) Example :
coins = [], amount =
return -. Note:
You may assume that you have an infinite number of each kind of coin.
一刷使用暴力递归,WA,没想明白为什么会WA!继续想。二刷使用DP算法,DP更新关键过程写错WA。
class Solution {
public:
int coinChange(vector<int>& coins, int amount) {
int MAX = amount + ;
vector<int> dp(MAX, MAX);
dp[] = ;
for (int i = ; i <= amount; i++) {
for (int n : coins) {
if (i >= n) {
dp[i] = min(dp[i], + dp[i - n]);
}
}
}
return dp[amount] < MAX ? dp[amount] : -;
}
};
dp
class Solution {
private:
int helper(const vector<int>& coins, int amount) {
if (amount == ) {
return ;
}
for (int n : coins) {
if (amount >= n) {
int res = helper(coins, amount - n);
if( res >= ) return + res;
}
}
return -;
}
public: int coinChange(vector<int>& coins, int amount) {
sort(coins.begin(), coins.end(), myComp);
return helper(coins, amount);
} static bool myComp(int i, int j) {
return i > j;
}
};
bad recursion
这个DP算法比较简单,状态方程也好想,只是初始化略不同,怎么就没想起来呢!再刷!
740. Delete and Earn
https://leetcode.com/contest/weekly-contest-61/problems/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] - or nums[i] + . You start with points. Return the maximum number of points you can earn by applying such operations. Example :
Input: nums = [, , ]
Output:
Explanation:
Delete to earn points, consequently is also deleted.
Then, delete to earn points. total points are earned.
Example :
Input: nums = [, , , , , ]
Output:
Explanation:
Delete to earn points, deleting both 's and the 4.
Then, delete again to earn points, and again to earn points.
total points are earned.
Note: The length of nums is at most .
Each element nums[i] is an integer in the range [, ].
DP,可以降为子问题,典型的0-1背包问题。要继续思考,细嚼慢咽还是很有收获的。
class Solution {
public:
int deleteAndEarn(vector<int>& nums) {
vector<int> scores(, ), dp(, );
for (int n : nums) scores[n] += n;
dp[] = scores[];
for (int i = ; i < ; i++) dp[i] = max(dp[i - ], dp[i - ] + scores[i]);
return dp[];
}
};
115. Distinct Subsequences
https://leetcode.com/problems/distinct-subsequences/description/
Given a string S and a string T, count the number of distinct subsequences of S which equals T. 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). Here is an example:
S = "rabbbit", T = "rabbit" Return .
DP。二维填表题,i-1和j-1分别是s和t的index,使用s[i-1]的匹配数为s[i-1]==t[j-1]时的dp[i-1][j-1],不使用s[i-1]时的匹配数为dp[i-1]][j]。
class Solution {
public:
int numDistinct(string s, string t) {
int m = s.size(), n = t.size();
vector<vector<int>> dp(m + , vector<int>(n + , ));
for (int i = ; i <= m; i++) dp[i][] = ;
for (int i = ; i <= m; i++) {
for (int j = ; j <= n; j++) dp[i][j] = dp[i - ][j] + (s[i - ] == t[j - ] ? dp[i - ][j - ] : );
}
return dp[m][n];
}
};
494. Target Sum
https://leetcode.com/problems/target-sum/description/
一刷没有好思路,看了大神的解析,将问题转化为一个之前解决过的相似问题,自己使用DFS解决了,但是过程不够顺畅,对于set的计数不能再t=0时直接返回,而应该结果+1。时间复杂度为O(N^2)再刷!二刷使用DP没AC,对vector::resize()理解不对,resize并不会对vector原有的数据进行重置,只会将其截断或者在后端补充,应该先用clear。时间复杂度为O(N^2), 空间复杂度为O(N)。再刷!
class Solution {
private:
int dfs(vector<int>& nums, int t, int s) {
if (t < ) {
return !t;
}
int res = ;
res += (t == ? : );
for (int i = s; i < nums.size(); i++) {
res += dfs(nums, t - nums[i], i + );
}
return res;
}
public:
int findTargetSumWays(vector<int>& nums, int S) {
long long total = accumulate(nums.begin(), nums.end(), );
long long t = total + S;
if (t % ) {
return ;
}
t /= ;
return dfs(nums, t, );
}
};
dfs
class Solution {
public:
int findTargetSumWays(vector<int>& nums, int S) {
long long t = accumulate(nums.begin(), nums.end(), );
if (S > t || S < -t) {
return ;
}
vector<int> d( * t + , ), n( * t + , ), *dp = &d, *next = &n;
dp->at(t) = ;
for (int i = ; i < nums.size(); i++) {
for (int j = ; j < * t + ; j++) {
if (dp->at(j) > ) {
next->at(j + nums[i]) += dp->at(j);
next->at(j - nums[i]) += dp->at(j);
}
}
swap(dp, next);
next->clear();
next->resize( * t + , );
}
return dp->at(t + S);
}
};
dp
DFS思路:将num分为正集合P和负集合N,于是有下面的推导:
sum(P) - sum(N) = target
sum(P) + sum(N) + sum(P) - sum(N) = target + sum(P) + sum(N)
2 * sum(P) = target + sum(nums)
现在问题也就变成了寻求满足条件的P的个数,可以用DFS。官方给每道题都给了答案,而且每道题的答案不止一种,再刷可以重点看看官方答案。
714. Best Time to Buy and Sell Stock with Transaction Fee
https://leetcode.com/problems/best-time-to-buy-and-sell-stock-with-transaction-fee/description/
Your are given an array of integers prices, for which the i-th element is the price of a given stock on day i; and a non-negative integer fee representing a transaction fee. You may complete as many transactions as you like, but you need to pay the transaction fee for each transaction. You may not buy more than share of a stock at a time (ie. you must sell the stock share before you buy again.) Return the maximum profit you can make. Example :
Input: prices = [, , , , , ], fee =
Output:
Explanation: The maximum profit can be achieved by:
Buying at prices[] =
Selling at prices[] =
Buying at prices[] =
Selling at prices[] =
The total profit is (( - ) - ) + (( - ) - ) = .
Note: < prices.length <= .
< prices[i] < .
<= fee < .
一刷使用122题中的贪心算法:先买,涨了就卖,这样是不对的,[1,3,7,5,10,3]这个case就不对。二刷使用s0和s1分别记录两种状态(有限状态自动机),s0是手里没有股票时的收益,s1是手里有一支股票时的收益,在两个状态之间切换,和309很像。
class Solution {
public:
int maxProfit(vector<int>& prices, int fee) {
int s0 = , s1 = INT_MIN;
for (int p : prices) {
int tmp = s0;
s0 = max(s0, s1 + p);
s1 = max(s1, s0 - p - fee);
}
return s0;
}
};
309. Best Time to Buy and Sell Stock with Cooldown
https://leetcode.com/problems/best-time-to-buy-and-sell-stock-with-cooldown/description/
Say you have an array for which the ith element is the price of a given stock on day i. Design an algorithm to find the maximum profit. You may complete as many transactions as you like (ie, buy one and sell one share of the stock multiple times) with the following restrictions: You may not engage in multiple transactions at the same time (ie, you must sell the stock before you buy again).
After you sell your stock, you cannot buy stock on next day. (ie, cooldown day)
Example: prices = [, , , , ]
maxProfit =
transactions = [buy, sell, cooldown, buy, sell]
一刷没思路,使用基于有限状态机的DP,一刷AC,时间复杂度和空间复杂度均为O(N)。s0,s1,s2三个状态分别表示最后一个操作为rest, buy, sell的当天maxprofit。再刷!
class Solution {
public:
int maxProfit(vector<int>& prices) {
int s = prices.size();
if (s < ) {
return ;
}
vector<int> s0(s, ), s1(s, ), s2(s, );
s0[] = ;
s1[] = -prices[];
s2[] = INT_MIN;
for (int i = ; i < s; i++) {
s0[i] = max(s0[i - ], s2[i - ]);
s1[i] = max(s0[i - ] - prices[i], s1[i - ]);
s2[i] = s1[i - ] + prices[i];
}
return max(s0[s - ], s2[s - ]);
}
};
state machine dp
304. Range Sum Query 2D - Immutable
https://leetcode.com/problems/range-sum-query-2d-immutable/description/
Given a 2D matrix matrix, find the sum of the elements inside the rectangle defined by its upper left corner (row1, col1) and lower right corner (row2, col2). Range Sum Query 2D
The above rectangle (with the red border) is defined by (row1, col1) = (, ) and (row2, col2) = (, ), which contains sum = . Example:
Given matrix = [
[, , , , ],
[, , , , ],
[, , , , ],
[, , , , ],
[, , , , ]
] sumRegion(, , , ) ->
sumRegion(, , , ) ->
sumRegion(, , , ) ->
Note:
You may assume that the matrix does not change.
There are many calls to sumRegion function.
You may assume that row1 ≤ row2 and col1 ≤ col2.
class NumMatrix {
private:
vector< vector<int> > sum;
int m = , n = ; //m * n.
public:
NumMatrix(vector<vector<int>> matrix) {
m = matrix.size();
if (m) {
n = matrix[].size(); // m * n
sum.resize(m, vector<int>(n, ));
sum[][] = matrix[][];
for (int i = ; i < m; i++) {
sum[i][] = matrix[i][] + sum[i - ][];
}
for (int j = ; j < n; j++) {
sum[][j] = matrix[][j] + sum[][j - ];
}
for (int i = ; i < m; i++) {
for (int j = ; j < n; j++) {
sum[i][j] = sum[i - ][j] + sum[i][j - ] + matrix[i][j] - sum[i - ][j - ];
}
}
} } int sumRegion(int row1, int col1, int row2, int col2) {
if (row1 < m && row2 < m && col1 < n && col2 < n) {
if (!row1 && !col1) {
return sum[row2][col2];
} else if (!row1 && col1) {
return sum[row2][col2] - sum[row2][col1 - ];
} else if (row1 && !col1) {
return sum[row2][col2] - sum[row1 - ][col2];
} else {
return sum[row2][col2] - sum[row2][col1 - ] - sum[row1 - ][col2] + sum[row1 - ][col1- ];
}
}
return ;
}
}; /**
* Your NumMatrix object will be instantiated and called as such:
* NumMatrix obj = new NumMatrix(matrix);
* int param_1 = obj.sumRegion(row1,col1,row2,col2);
*/
dp
一刷没判断二维数组维度为0的情况没AC,使用DP,时间复杂度和空间复杂度均为O(M*N),效率不高,二刷关键是调研更优秀的解法。
474. Ones and Zeroes
https://leetcode.com/problems/ones-and-zeroes/description/
In the computer world, use restricted resource you have to generate maximum benefit is what we always want to pursue. For now, suppose you are a dominator of m 0s and n 1s respectively. On the other hand, there is an array with strings consisting of only 0s and 1s. Now your task is to find the maximum number of strings that you can form with given m 0s and n 1s. Each and can be used at most once. Note:
The given numbers of 0s and 1s will both not exceed
The size of given string array won't exceed 600.
Example :
Input: Array = {"", "", "", "", ""}, m = , n =
Output: Explanation: This are totally strings can be formed by the using of 0s and 1s, which are “,””,””,””
Example :
Input: Array = {"", "", ""}, m = , n =
Output: Explanation: You could form "", but then you'd have nothing left. Better form "0" and "1".
class Solution {
public:
int findMaxForm(vector<string>& strs, int m, int n) {
vector< vector<int> > dp(m + , vector<int> (n + , ));
for (string s : strs) {
int zeros = count(s.begin(), s.end(), '');
int ones = s.size() - zeros;
for (int i = m; i >= zeros; i--) {
for (int j = n; j >= ones; j--) {
dp[i][j] = max(dp[i][j], dp[i - zeros][j - ones] + );
}
}
}
return dp[m][n];
}
};
dp
class Solution {
public:
static bool myComp(string s1, string s2) {
return s1.size() < s2.size();
}
int findMaxForm(vector<string>& strs, int m, int n) {
vector< vector< bitset<> > > dp(m + , vector< bitset<> > (n + , bitset<>()));
sort(strs.begin(), strs.end(), myComp);
int sum1 = , sum0 = ;
for (int i = ; i < strs.size(); i++) {
if (count(strs[i].begin(), strs[i].end(), '') == strs[i].size()) {
if (sum1 + strs[i].size() <= n) {
sum1 += strs[i].size();
dp[][sum1] = dp[][sum1 - strs[i].size()];
dp[][sum1].set(i);
}
} else if (count(strs[i].begin(), strs[i].end(), '') == ) {
if (sum0 + strs[i].size() <= n) {
sum0 += strs[i].size();
dp[sum0][] = dp[sum0 - strs[i].size()][];
dp[sum0][].set(i);
}
}
}
for (int i = ; i < m; i++) {
if (dp[i][].count() == ) {
dp[i][] = dp[i - ][];
}
}
for (int j = ; j < n; j++) {
if (dp[][j].count() == ) {
dp[][j] = dp[][j - ];
}
}
for (int i = ; i < m; i++) {
for (int j = ; j < n; j++) {
for (int k = ; k < strs.size(); k++) {
int zeros = count(strs[i].begin(), strs[i].end(), '');
int ones = strs[i].size() - zeros;
if (i - zeros >= && j - ones >= && !dp[i - zeros][j - ones].test(k) && dp[i - zeros][j - ones].count() + > dp[i][j].count()) {
dp[i][j] = dp[i - zeros][j - ones];
dp[i][j].set(k);
}
}
if (!(dp[i][j].count() > dp[i - ][j].count() && dp[i][j].count() > dp[i][j].count())) {
dp[i][j - ].count() > dp[i - ][j].count() ? dp[i][j] = dp[i][j - ] : dp[i][j] = dp[i - ][j];
}
}
}
return dp[m][n].count();
}
};
my_failed_dp
class Solution {
private:
int dfs(bitset<>& s, vector<string>& strs, int m, int n, int b) {
if (m < || n < ) {
return s.count() - ;
} else if ((m == && n == ) || (b >= strs.size())) {
return s.count();
}
int res = ;
for (int i = b; i < strs.size(); i++) {
if (!(s.test(i))) {
int zeros = count(strs[i].begin(), strs[i].end(), '');
res = max(res, dfs(s.set(i), strs, m - zeros, n - (strs[i].size() - zeros), i + ));
s.reset(i);
}
}
return res;
}
public:
int findMaxForm(vector<string>& strs, int m, int n) {
bitset<> s();
return dfs(s, strs, m, n, );
}
};
TLE-brute_force_dfs
一刷使用暴力DFS,TLE。bitset的使用得到了锻炼,bitset使用set和reset进行赋值,使用test测试位,使用count度量位。二刷使用DP,出了bug,没调通。三刷使用大神的空间复杂度O(M*N),时间复杂度O(M*N*L)的DP算法,一次AC。大神的思路并不好理解,再刷!注意理解!
375. Guess Number Higher or Lower II
https://leetcode.com/problems/guess-number-higher-or-lower-ii/description/
We are playing the Guess Game. The game is as follows: I pick a number from to n. You have to guess which number I picked. Every time you guess wrong, I'll tell you whether the number I picked is higher or lower. However, when you guess a particular number x, and you guess wrong, you pay $x. You win the game when you guess the number I picked. Example: n = , I pick . First round: You guess , I tell you that it's higher. You pay $5.
Second round: You guess , I tell you that it's higher. You pay $7.
Third round: You guess , I tell you that it's lower. You pay $9. Game over. is the number I picked. You end up paying $ + $ + $ = $.
Given a particular n ≥ , find out how much money you need to have to guarantee a win.
一刷使用dp思路不对,问题没想清楚,总想着用二分法,事实上二分法的结果并非最优!二刷使用大神的bottom-up的DP,没有一次AC,对DP的更新过程理解不够,再刷,注意理解。
class Solution {
public:
int getMoneyAmount(int n) {
vector< vector<int> > dp(n + , vector<int> (n + , ));
for (int j = ; j <= n; j++) {
for (int i = j - ; i > ; i--) {
int m = INT_MAX;
for (int k = i + ; k < j; k++) {
int local_max = k + max(dp[i][k - ], dp[k + ][j]);
m = min(m, local_max);
}
dp[i][j] = (i + == j ? i : m);
}
}
return dp[][n];
}
};
638. Shopping Offers
https://leetcode.com/problems/shopping-offers/description/
In LeetCode Store, there are some kinds of items to sell. Each item has a price. However, there are some special offers, and a special offer consists of one or more different kinds of items with a sale price. You are given the each item's price, a set of special offers, and the number we need to buy for each item. The job is to output the lowest price you have to pay for exactly certain items as given, where you could make optimal use of the special offers. Each special offer is represented in the form of an array, the last number represents the price you need to pay for this special offer, other numbers represents how many specific items you could get if you buy this offer. You could use any of special offers as many times as you want. Example :
Input: [,], [[,,],[,,]], [,]
Output:
Explanation:
There are two kinds of items, A and B. Their prices are $ and $ respectively.
In special offer , you can pay $ for 3A and 0B
In special offer , you can pay $ for 1A and 2B.
You need to buy 3A and 2B, so you may pay $ for 1A and 2B (special offer #), and $ for 2A.
Example :
Input: [,,], [[,,,],[,,,]], [,,]
Output:
Explanation:
The price of A is $, and $ for B, $ for C.
You may pay $ for 1A and 1B, and $ for 2A ,2B and 1C.
You need to buy 1A ,2B and 1C, so you may pay $ for 1A and 1B (special offer #), and $ for 1B, $ for 1C.
You cannot add more items, though only $ for 2A ,2B and 1C.
Note:
There are at most kinds of items, special offers.
For each item, you need to buy at most of them.
You are not allowed to buy more items than you want, even if that would lower the overall price.
自己思考的时候,没想到把list转为int。一刷使用自己设计的DP方法,WA。二刷使用带memo的dfs,这是top-down的dp,但是我更熟悉bottom-up的dp。由于把变量k写成key(这也是变量名设计问题),一直WA,debug很久。思路比较清晰,我自己两个思路都想明白了,但是手生。再刷!再刷注意实现自己的bottom-up的dp。
class Solution {
private:
vector<int> pow;
int getKey(vector<int> nums) {
int s = nums.size();
int res = ;
for (int i = s - , p = ; i >= ; i--, p *= ) {
res += nums[i] * p;
}
return res;
} int dfs(const vector<int>& price, vector<vector<int>>& special, unordered_map<int, int>& m, int k) {
if (m.count(k)) {
return m[k];
}
int ans = , n = price.size();
for (int i = ; i < n; i++) {
ans += price[i] * ((k / pow[i]) % );
} for (auto sp : special) {
int key = , i = , t = ;
while (i < n) {
int itemC = (k / pow[i]) % ;
if (sp[i] <= itemC) {
key += pow[i] * (itemC - sp[i++]);
} else {
break;
}
}
if (i == n) {
ans = min(ans, sp[n] + dfs(price, special, m, key));
}
}
return m[k] = ans;
} public:
int shoppingOffers(vector<int>& price, vector<vector<int>>& special, vector<int>& needs) {
int s = needs.size();
if (s < ) {
return ;
}
pow.clear();
pow.resize(s, );
for (int i = s - ; i >= ; i--) {
pow[i] = pow[i + ] * ;
}
unordered_map<int, int> m;
int key = getKey(needs);
return dfs(price, special, m, key);
} };
690. Employee Importance
https://leetcode.com/problems/employee-importance/description/
You are given a data structure of employee information, which includes the employee's unique id, his importance value and his direct subordinates' id. For example, employee is the leader of employee , and employee is the leader of employee . They have importance value , and , respectively. Then employee has a data structure like [, , []], and employee has [, , []], and employee has [, , []]. Note that although employee is also a subordinate of employee , the relationship is not direct. Now given the employee information of a company, and an employee id, you need to return the total importance value of this employee and all his subordinates. Example :
Input: [[, , [, ]], [, , []], [, , []]],
Output:
Explanation:
Employee has importance value , and he has two direct subordinates: employee and employee . They both have importance value . So the total importance value of employee is + + = .
Note:
One employee has at most one direct leader and may have several subordinates.
The maximum number of employees won't exceed 2000.
一刷使用DFS暴力递归AC。效率低,时间复杂度为O(LN),空间复杂度为O(L),L为下属员工总个数(包括非直接下属),N为员工总数。再刷尝试高效解法。
/*
// Employee info
class Employee {
public:
// It's the unique ID of each node.
// unique id of this employee
int id;
// the importance value of this employee
int importance;
// the id of direct subordinates
vector<int> subordinates;
};
*/
class Solution {
public:
int getImportance(vector<Employee*> employees, int id) {
int res = ;
for (auto e : employees) {
if (e->id == id) {
res += e->importance;
for (int sub_id : e->subordinates) {
res += getImportance(employees, sub_id);
}
}
}
return res;
}
};
brute-force-dfs
513. Find Bottom Left Tree Value
https://leetcode.com/problems/find-bottom-left-tree-value/description/
Given a binary tree, find the leftmost value in the last row of the tree. Example :
Input: / \ Output: Example :
Input: / \ / / \ / Output: Note: You may assume the tree (i.e., the given root node) is not NULL.
一刷使用DFS暴力递归AC,效率低。时、空间复杂度O(L^2),因为递归深度为L,查深度和查最左下元素都要递归到最底层。再刷要使用高效解法。二刷使用较为高效的dfs解法,
但是不太理解大神的思路。再刷!
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
private:
int get_level(TreeNode* r) {
if (!r) {
return ;
}
return + max(get_level(r->left), get_level(r->right));
}
public:
int findBottomLeftValue(TreeNode* root) {
int l = get_level(root->left), r = get_level(root->right);
if (l >= r && l > ) {
return findBottomLeftValue(root->left);
} else if (l < r && r > ) {
return findBottomLeftValue(root->right);
} else {
return root->val;
}
}
};
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
private:
void dfs(TreeNode* root, int& max_level, int& res, int d) {
if (!root) {
return;
}
dfs(root->left, max_level, res, d+);
dfs(root->right, max_level, res, d+);
if (d > max_level) {
max_level = d;
res = root->val;
}
}
public:
int findBottomLeftValue(TreeNode* root) {
int res = root->val;
int max_level = ;
dfs(root, max_level, res, );
return res;
}
};
693. Binary Number with Alternating Bits
https://leetcode.com/problems/binary-number-with-alternating-bits/description/
Given a positive integer, check whether it has alternating bits: namely, if two adjacent bits will always have different values. Example :
Input:
Output: True
Explanation:
The binary representation of is:
Example :
Input:
Output: False
Explanation:
The binary representation of is: .
Example :
Input:
Output: False
Explanation:
The binary representation of is: .
Example :
Input:
Output: True
Explanation:
The binary representation of is: .
一刷没AC,忘记更新ex。时间复杂度为O(log N),空间复杂度为O(1)。
class Solution {
public:
bool hasAlternatingBits(int n) {
if (n < ) {
return true;
}
int ex = n % ;
n >>= ;
while (n) {
int b = n % ;
if (!(b ^ ex)) {
return false;
}
ex = b;
n >>= ;
}
return true;
}
};
691. Stickers to Spell Word
https://leetcode.com/problems/stickers-to-spell-word/description/
We are given N different types of stickers. Each sticker has a lowercase English word on it. You would like to spell out the given target string by cutting individual letters from your collection of stickers and rearranging them. You can use each sticker more than once if you want, and you have infinite quantities of each sticker. What is the minimum number of stickers that you need to spell out the target? If the task is impossible, return -. Example : Input: ["with", "example", "science"], "thehat"
Output: Explanation: We can use "with" stickers, and "example" sticker.
After cutting and rearrange the letters of those stickers, we can form the target "thehat".
Also, this is the minimum number of stickers necessary to form the target string.
Example : Input: ["notice", "possible"], "basicbasic"
Output: -
Explanation: We can't form the target "basicbasic" from cutting letters from the given stickers.
Note: stickers has length in the range [, ].
stickers consists of lowercase English words (without apostrophes).
target has length in the range [, ], and consists of lowercase English letters.
In all test cases, all words were chosen randomly from the most common US English words, and the target was chosen as a concatenation of two random words.
The time limit may be more challenging than usual. It is expected that a sticker test case can be solved within 35ms on average.
一刷没思路,套用大神的思路是带memo的DFS,思路很清晰,一刷AC。时、空间复杂度为O(N),递归深度也是N。手生,再刷。
class Solution {
private:
int dfs(unordered_map<string, int>& dp, const vector<vector<int>>& mp, string target) {
if (dp.count(target)) {
return dp[target];
}
vector<int> tar(, );
for (char c : target) {
tar[c - 'a']++;
}
// apply every sticker and get the minimus ans as res;
int ans = INT_MAX; for (auto sticker : mp) {
string s;
for (int i = ; i < ; i++) {
if (tar[i]) {
s += string(max(, tar[i] - sticker[i]), 'a' + i);
}
}
if (s.size() < target.size()) {
int tmp = dfs(dp, mp, s);
if (tmp != -) {
ans = min(ans, + tmp);
}
}
}
return dp[target] = ans == INT_MAX ? - : ans;
}
public:
int minStickers(vector<string>& stickers, string target) {
int m = stickers.size();
vector<vector<int>> mp(m, vector<int> (, ));
for (int i = ; i < m; i++) {
for (char c : stickers[i]) {
mp[i][c - 'a'] ++;
}
}
unordered_map<string, int> dp;
dp[""] = ;
return dfs(dp, mp, target);
}
};
695. Max Area of Island
https://leetcode.com/problems/max-area-of-island/description/
Given a non-empty 2D array grid of 's and 1's, an island is a group of 's (representing land) connected 4-directionally (horizontal or vertical.) You may assume all four edges of the grid are surrounded by water. Find the maximum area of an island in the given 2D array. (If there is no island, the maximum area is .) Example :
[[,,,,,,,,,,,,],
[,,,,,,,,,,,,],
[,,,,,,,,,,,,],
[,,,,,,,,,,,,],
[,,,,,,,,,,,,],
[,,,,,,,,,,,,],
[,,,,,,,,,,,,],
[,,,,,,,,,,,,]]
Given the above grid, return . Note the answer is not , because the island must be connected -directionally.
Example :
[[,,,,,,,]]
Given the above grid, return .
一刷AC,关键思想是算法核心使用dfs,利用queue存储中间结果,原地更改数组。时间复杂度为O(M*N),空间复杂度为O(1)。
class Solution {
public:
int maxAreaOfIsland(vector<vector<int>>& grid) {
int res = , m = grid.size(), n = grid[].size(); // grid is m * n.
vector<int> bias_r = {, , , -};
vector<int> bias_c = {, -, , };
for (int i = ; i < m; i++) {
for (int j = ; j < n; j++) {
if (grid[i][j]) {
int tmp = ;
queue<int> q; // q[i] = 100 * row + col;
q.push(i * + j);
grid[i][j] = ;
while (!q.empty()) {
int head = q.front();
q.pop();
int r = head / , c = head % ;
for (int k = ; k < ; k++) {
int new_r = r + bias_r[k], new_c = c + bias_c[k];
if (new_r >= && new_r < m && new_c >= && new_c < n && grid[new_r][new_c]) {
q.push( * new_r + new_c);
tmp++;
grid[new_r][new_c] = ;
}
} }
res = max(res, tmp);
}
}
}
return res;
}
};
733. Flood Fill
https://leetcode.com/contest/weekly-contest-60/problems/flood-fill/
An image is represented by a -D array of integers, each integer representing the pixel value of the image (from to ). Given a coordinate (sr, sc) representing the starting pixel (row and column) of the flood fill, and a pixel value newColor, "flood fill" the image. To perform a "flood fill", consider the starting pixel, plus any pixels connected -directionally to the starting pixel of the same color as the starting pixel, plus any pixels connected -directionally to those pixels (also with the same color as the starting pixel), and so on. Replace the color of all of the aforementioned pixels with the newColor. At the end, return the modified image. Example :
Input:
image = [[,,],[,,],[,,]]
sr = , sc = , newColor =
Output: [[,,],[,,],[,,]]
Explanation:
From the center of the image (with position (sr, sc) = (, )), all pixels connected
by a path of the same color as the starting pixel are colored with the new color.
Note the bottom corner is not colored , because it is not -directionally connected
to the starting pixel.
Note: The length of image and image[] will be in the range [, ].
The given starting pixel will satisfy <= sr < image.length and <= sc < image[].length.
The value of each color in image[i][j] and newColor will be an integer in [, ].
Discuss
dfs, 注意将访问过的节点设置为特殊字符,然后再变回来,防止死循环。
class Solution {
private:
int m, n, oldColor;
int bias[] = {, , -, , };
void dfs (vector<vector<int>>& image, int sr, int sc, int newColor) {
if (sr < || sr >= m || sc < || sc > n || image[sr][sc] != oldColor) return;
image[sr][sc] = -;
for (int i = ; i < ; i++) {
int new_r = sr + bias[i], new_c = sc + bias[i + ];
dfs(image, new_r, new_c, newColor);
}
}
public:
vector<vector<int>> floodFill(vector<vector<int>>& image, int sr, int sc, int newColor) {
m = image.size(), n = image[].size();
oldColor = image[sr][sc];
dfs(image, sr, sc, newColor);
for (int i = ; i < m; i++) {
for (int j = ; j < n; j++) {
if (image[i][j] == -) image[i][j] = newColor;
}
}
return image;
}
};
694. Number of Distinct Islands
https://leetcode.com/contest/leetcode-weekly-contest-53/problems/number-of-distinct-islands/
Given a non-empty 2D array grid of 's and 1's, an island is a group of 's (representing land) connected 4-directionally (horizontal or vertical.) You may assume all four edges of the grid are surrounded by water. Count the number of distinct islands. An island is considered to be the same as another if and only if one island can be translated (and not rotated or reflected) to equal the other. Example : Given the above grid map, return .
Example : Given the above grid map, return . Notice that: and are considered different island shapes, because we do not consider reflection / rotation.
Note: The length of each dimension in the given grid does not exceed .
一刷没有想到怎么表示多个岛之间的“translation”的关系,题意不太理解,跟上题很像,只需要用set记录编码之后的island的所有node,最后返回set的长度即可。还学到了访问matrix一个元素四周邻居的更省空间的方式,数组bias设置为[1, 0, -1, 0, 1]即可,每次访问row的bias为bias[i],column的bias为bias[i + 1],非常巧妙!这个题目对于非付费用户依据*了,尽快再刷一次。
class Solution {
public:
int numDistinctIslands(vector<vector<int>>& grid) {
int m = grid.size(), n = grid[].size(); // grid is m * n.
vector<int> bias = {, , -, , };
set<vector<int>> islands; // set[i] = (r - base_r) * 100 + (c - base_c)
for (int i = ; i < m; i++) {
for (int j = ; j < n; j++) {
if (grid[i][j]) {
int tmp = ;
queue<int> q; // q[i] = 100 * row + col;
q.push(i * + j);
grid[i][j] = ;
vector<int> island;
island.push_back();
while (!q.empty()) {
int head = q.front();
q.pop();
int r = head / , c = head % ;
for (int k = ; k < ; k++) {
int new_r = r + bias[k], new_c = c + bias[k + ];
if (new_r >= && new_r < m && new_c >= && new_c < n && grid[new_r][new_c]) {
q.push( * new_r + new_c);
grid[new_r][new_c] = ;
island.push_back((new_r - i) * + (new_c - j));
}
}
}
islands.insert(island);
}
}
}
return islands.size();
}
};
496. Next Greater Element I
https://leetcode.com/problems/next-greater-element-i/description/
You are given two arrays (without duplicates) nums1 and nums2 where nums1’s elements are subset of nums2. Find all the next greater numbers for nums1's elements in the corresponding places of nums2. The Next Greater Number of a number x in nums1 is the first greater number to its right in nums2. If it does not exist, output - for this number. Example :
Input: nums1 = [,,], nums2 = [,,,].
Output: [-,,-]
Explanation:
For number in the first array, you cannot find the next greater number for it in the second array, so output -.
For number in the first array, the next greater number for it in the second array is .
For number in the first array, there is no next greater number for it in the second array, so output -.
Example :
Input: nums1 = [,], nums2 = [,,,].
Output: [,-]
Explanation:
For number in the first array, the next greater number for it in the second array is .
For number in the first array, there is no next greater number for it in the second array, so output -.
Note:
All elements in nums1 and nums2 are unique.
The length of both nums1 and nums2 would not exceed .
一刷没思路,借鉴大神基于stack的思路AC。思路很奇妙,还需深入理解。二刷AC,简化了代码。
class Solution {
public:
vector<int> nextGreaterElement(vector<int>& findNums, vector<int>& nums) {
stack<int> s;
unordered_map<int, int> m;
for (int n : nums) {
while (!s.empty() && s.top() < n) {
m[s.top()] = n;
s.pop();
}
s.push(n);
}
vector<int> res;
for (int n : findNums) {
res.push_back(m.find(n) == m.end() ? - : m[n]);
}
return res;
}
};
503. Next Greater Element II
https://leetcode.com/problems/next-greater-element-ii/description/
Given a circular array (the next element of the last element is the first element of the array), print the Next Greater Number for every element. The Next Greater Number of a number x is the first greater number to its traversing-order next in the array, which means you could search circularly to find its next greater number. If it doesn't exist, output -1 for this number. Example :
Input: [,,]
Output: [,-,]
Explanation: The first 's next greater number is 2;
The number can't find next greater number;
The second 's next greater number needs to search circularly, which is also 2.
Note: The length of given array won't exceed 10000.
一刷使用和上题相似的思路,没想清楚,WA。本题中有重复元素,stack和map都要保存index,和上题的区别在于要进行两次遍历,算法效率还可以继续提升。时间和空间复杂度为O(N)。再刷。
class Solution {
public:
vector<int> nextGreaterElements(vector<int>& nums) {
unordered_map<int, int> m;
stack<int> s;
for (int i = ; i < nums.size(); i++) {
while (!s.empty() && nums[s.top()] < nums[i]) {
m[s.top()] = nums[i];
s.pop();
}
s.push(i);
}
for (int i = ; i < nums.size(); i++) {
while (!s.empty() && nums[s.top()] < nums[i]) {
if (m.find(s.top()) == m.end()) {
m[s.top()] = nums[i];
}
s.pop();
}
s.push(i);
}
for (int i = ; i < nums.size(); i++) {
nums[i] = (m.find(i) == m.end() ? - : m[i]);
}
return nums;
}
};
144. Binary Tree Preorder Traversal
https://leetcode.com/problems/binary-tree-preorder-traversal/description/
Given a binary tree, return the preorder traversal of its nodes' values. For example:
Given binary tree {,#,,}, \ / return [,,]. Note: Recursive solution is trivial, could you do it iteratively?
二叉树先序遍历,一刷递归AC。二刷使用非递归算法一次AC,注意入栈的时先对右子树入栈,再对左子树入栈,从而保证左子树优先访问。
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
private:
void helper(TreeNode* root, vector<int> & res) {
if (root) {
res.push_back(root->val);
helper(root->left, res);
helper(root->right, res);
}
}
public:
vector<int> preorderTraversal(TreeNode* root) {
vector<int> res;
helper(root, res);
return res;
}
};
recursion
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
vector<int> preorderTraversal(TreeNode* root) {
vector<int> res;
if (!root) {
return res;
}
stack<TreeNode *> s;
s.push(root);
while (!s.empty()) {
auto node = s.top();
s.pop();
if (node) {
res.push_back(node->val);
s.push(node->right);
s.push(node->left);
}
}
return res;
}
};
none-recursion
341. Flatten Nested List Iterator
https://leetcode.com/problems/flatten-nested-list-iterator/description/
Given a nested list of integers, implement an iterator to flatten it. Each element is either an integer, or a list -- whose elements may also be integers or other lists. Example :
Given the list [[,],,[,]], By calling next repeatedly until hasNext returns false, the order of elements returned by next should be: [,,,,]. Example :
Given the list [,[,[]]], By calling next repeatedly until hasNext returns false, the order of elements returned by next should be: [,,].
一刷思路不对,使用大神的思路一刷没有AC,思路不易理解,但是跟我的思路相似。再刷,深入理解大神的算法。
/**
* // This is the interface that allows for creating nested lists.
* // You should not implement it, or speculate about its implementation
* class NestedInteger {
* public:
* // Return true if this NestedInteger holds a single integer, rather than a nested list.
* bool isInteger() const;
*
* // Return the single integer that this NestedInteger holds, if it holds a single integer
* // The result is undefined if this NestedInteger holds a nested list
* int getInteger() const;
*
* // Return the nested list that this NestedInteger holds, if it holds a nested list
* // The result is undefined if this NestedInteger holds a single integer
* const vector<NestedInteger> &getList() const;
* };
*/
class NestedIterator {
private:
stack< vector<NestedInteger>::iterator > begins, ends;
public:
NestedIterator(vector<NestedInteger> &nestedList) {
begins.push(nestedList.begin());
ends.push(nestedList.end());
} int next() {
return (begins.top()++)->getInteger();
} bool hasNext() {
while (!begins.empty()) {
if (begins.top() == ends.top()) {
begins.pop();
ends.pop();
} else {
auto it = begins.top();
if (it->isInteger()) {
return true;
}
begins.top()++;
begins.push(it->getList().begin());
ends.push(it->getList().end());
}
}
return false;
}
}; /**
* Your NestedIterator object will be instantiated and called as such:
* NestedIterator i(nestedList);
* while (i.hasNext()) cout << i.next();
*/
173. Binary Search Tree Iterator
https://leetcode.com/problems/binary-search-tree-iterator/description/
Implement an iterator over a binary search tree (BST). Your iterator will be initialized with the root node of a BST. Calling next() will return the next smallest number in the BST. Note: next() and hasNext() should run in average O() time and uses O(h) memory, where h is the height of the tree.
一刷按照和上题相似的思路,初始化时,遍历查找最左节点没有更新root,导致内存溢出。时间复杂度为O(N),空间复杂度为O(H)。二刷一次AC,精简了代码。
/**
* Definition for binary tree
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class BSTIterator {
private:
stack<TreeNode*> s;
public:
BSTIterator(TreeNode *root) {
if (root) {
s.push(root);
while (s.top()->left) {
s.push(s.top()->left);
}
}
} /** @return whether we have a next smallest number */
bool hasNext() {
return !s.empty();
} /** @return the next smallest number */
int next() {
auto node = s.top();
s.pop();
if (node->right) {
s.push(node->right);
while (s.top()->left) {
s.push(s.top()->left);
}
}
return node->val;
}
}; /**
* Your BSTIterator will be called like this:
* BSTIterator i = BSTIterator(root);
* while (i.hasNext()) cout << i.next();
*/
394. Decode String
https://leetcode.com/problems/decode-string/description/
Given an encoded string, return it's decoded string. The encoding rule is: k[encoded_string], where the encoded_string inside the square brackets is being repeated exactly k times. Note that k is guaranteed to be a positive integer. You may assume that the input string is always valid; No extra white spaces, square brackets are well-formed, etc. Furthermore, you may assume that the original data does not contain any digits and that digits are only for those repeat numbers, k. For example, there won't be input like 3a or 2[4]. Examples: s = "3[a]2[bc]", return "aaabcbc".
s = "3[a2[c]]", return "accaccacc".
s = "2[abc]3[cd]ef", return "abcabccdcdcdef".
一刷使用自己的算法WA。二刷使用大神的算法AC,使用两个stack分别存放“[x]”出现时之前的num和应该加到num * "[x]"之前的string,每个元素只表示一层,跟上层无关。思路理解了,但是还不熟,再刷。三刷使用递归算法,运行时间少于非递归算法,没有AC,思路不是很清楚,再刷。
class Solution {
public:
string decodeString(string s) {
stack<string> chars;
stack<int> nums;
string res;
int n = ;
for (char c : s) {
if (isdigit(c)) {
n = n * + c - '';
} else if (isalpha(c)) {
res += c;
} else if (c == '[') {
chars.push(res);
nums.push(n);
n = ;
res = "";
} else if (c == ']') {
string tmp;
while (nums.top()--) {
tmp += res;
}
res = chars.top() + tmp;
chars.pop();
nums.pop();
}
}
return res;
}
};
none-recursion
class Solution {
private:
string decodeString(const string& s, int& i) {
string res;
while (i < s.size() && s[i] != ']') {
if (!isdigit(s[i])) {
res += s[i++];
} else {
int n = ;
while (i < s.size() && isdigit(s[i])) {
n = n * + s[i++] - '';
}
i++;
string t = decodeString(s, i);
i++;
while (n-- > ) {
res += t;
}
}
}
return res;
}
public:
string decodeString(string s) {
int i = ;
return decodeString(s, i);
}
};
recursion
331. Verify Preorder Serialization of a Binary Tree
https://leetcode.com/problems/verify-preorder-serialization-of-a-binary-tree/description/
One way to serialize a binary tree is to use pre-order traversal. When we encounter a non-null node, we record the node's value. If it is a null node, we record using a sentinel value such as #. _9_
/ \ / \ / \
#
/ \ / \ / \
# # # # # #
For example, the above binary tree can be serialized to the string "9,3,4,#,#,1,#,#,2,#,6,#,#", where # represents a null node. Given a string of comma separated values, verify whether it is a correct preorder traversal serialization of a binary tree. Find an algorithm without reconstructing the tree. Each comma separated value in the string must be either an integer or a character '#' representing null pointer. You may assume that the input format is always valid, for example it could never contain two consecutive commas such as "1,,3". Example :
"9,3,4,#,#,1,#,#,2,#,6,#,#"
Return true Example :
"1,#"
Return false Example :
"9,#,#,1"
Return false
一刷使用自己的算法,没AC,看了讨论区,有大佬和我的算法相同,稍微修改了自己的代码AC。注意考虑两点,数的长度不止为1,中间过程如果stack为空,直接返回false即可。再刷一次。
class Solution {
public:
bool isValidSerialization(string preorder) {
stack<char> s;
for (int i = ; i < preorder.size(); i++) {
if (preorder[i] != '#' && preorder[i] != ',') {
s.push(preorder[i]);
while (preorder[i] != ',') {
i++;
}
} else if (preorder[i] == '#') {
while (!s.empty() && s.top() == '#') {
s.pop();
if (s.empty()) {
return false;
}
s.pop();
}
s.push('#');
}
}
return s.top() == '#' && s.size() == ;
}
};
103. Binary Tree Zigzag Level Order Traversal
https://leetcode.com/problems/binary-tree-zigzag-level-order-traversal/description/
Given a binary tree, return the zigzag level order traversal of its nodes' values. (ie, from left to right, then right to left for the next level and alternate between). For example:
Given binary tree [,,,null,null,,], / \ / \ return its zigzag level order traversal as:
[
[],
[,],
[,]
]
BFS,deque。
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
vector<vector<int>> zigzagLevelOrder(TreeNode* root) {
vector<vector<int>> res;
if (!root) return res;
deque<TreeNode*> q, next;
q.push_back(root);
int layer = ;
while (!q.empty()) {
vector<int> v;
while (!q.empty()) {
TreeNode* cur = NULL;
if ((layer & ) == ) {
cur = q.front(); q.pop_front();
if (cur->right) next.push_back(cur->right);
if (cur->left) next.push_back(cur->left);
} else {
cur = q.back(); q.pop_back();
if (cur->left) next.push_front(cur->left);
if (cur->right) next.push_front(cur->right);
}
v.push_back(cur->val);
}
swap(q, next);
res.push_back(v);
layer++;
}
return res;
}
};
150. Evaluate Reverse Polish Notation
https://leetcode.com/problems/evaluate-reverse-polish-notation/description/
Evaluate the value of an arithmetic expression in Reverse Polish Notation. Valid operators are +, -, *, /. Each operand may be an integer or another expression. Some examples:
["", "", "+", "", "*"] -> (( + ) * ) ->
["", "", "", "/", "+"] -> ( + ( / )) ->
一刷AC,注意先出栈的第二个操作数,后出栈的是第一个操作数。
class Solution {
public:
int evalRPN(vector<string>& tokens) {
stack<int> s;
for (string t : tokens) {
if (t != "+" && t != "-" && t != "*" && t != "/") {
s.push(stoi(t));
} else {
int e1 = s.top();
s.pop();
int e2 = s.top();
s.pop();
if (t == "+") {
s.push(e2 + e1);
} else if (t == "-") {
s.push(e2 - e1);
} else if (t == "*") {
s.push(e2 * e1);
} else {
s.push(e2 / e1);
}
}
}
return s.empty() ? : s.top();
}
};
456. 132 Pattern
https://leetcode.com/problems/132-pattern/description/
Given a sequence of n integers a1, a2, ..., an, a pattern is a subsequence ai, aj, ak such that i < j < k and ai < ak < aj. Design an algorithm that takes a list of n numbers as input and checks whether there is a pattern in the list. Note: n will be less than ,. Example :
Input: [, , , ] Output: False Explanation: There is no pattern in the sequence.
Example :
Input: [, , , ] Output: True Explanation: There is a pattern in the sequence: [, , ].
Example :
Input: [-, , , ] Output: True Explanation: There are three patterns in the sequence: [-, , ], [-, , ] and [-, , ].
一刷没思路,使用大神的算法,一次AC,但是理解不透彻。关键不太理解为什么要用while循环,是为了使用更大的中间值?再刷。
class Solution {
public:
bool find132pattern(vector<int>& nums) {
int s3 = INT_MIN, n = nums.size();
stack<int> s;
for (int i = n - ; i>= ; i--) {
if (nums[i] < s3) {
return true;
}
while (!s.empty() && s.top() < nums[i]) {
s3 = s.top();
s.pop();
}
s.push(nums[i]); }
return false;
}
};
402. Remove K Digits
https://leetcode.com/problems/remove-k-digits/description/
Given a non-negative integer num represented as a string, remove k digits from the number so that the new number is the smallest possible. Note:
The length of num is less than and will be ≥ k.
The given num does not contain any leading zero.
Example : Input: num = "", k =
Output: ""
Explanation: Remove the three digits , , and to form the new number which is the smallest.
Example : Input: num = "", k =
Output: ""
Explanation: Remove the leading and the number is . Note that the output must not contain leading zeroes.
Example : Input: num = "", k =
Output: ""
Explanation: Remove all the digits from the number and it is left with nothing which is .
一刷没思路,使用大神的算法,因为没注意循环过程中k会更新导致WA,debug很久。再刷!
class Solution {
public:
string removeKdigits(string num, int k) {
string s;
int d = num.size() - k;
for (char c : num) {
while (s.size() && s.back() > c && k > ) {
s.pop_back();
k--;
}
s += c;
}
int i = ;
while (i < d && s[i] == '') {
i++;
}
return i == (d) ? "" : s.substr(i, d - i);
}
};
636. Exclusive Time of Functions
https://leetcode.com/problems/exclusive-time-of-functions/description/
Given the running logs of n functions that are executed in a nonpreemptive single threaded CPU, find the exclusive time of these functions. Each function has a unique id, start from to n-. A function may be called recursively or by another function. A log is a string has this format : function_id:start_or_end:timestamp. For example, "0:start:0" means function starts from the very beginning of time . "0:end:0" means function ends to the very end of time . Exclusive time of a function is defined as the time spent within this function, the time spent by calling other functions should not be considered as this function's exclusive time. You should return the exclusive time of each function sorted by their function id. Example :
Input:
n =
logs =
["0:start:0",
"1:start:2",
"1:end:5",
"0:end:6"]
Output:[, ]
Explanation:
Function starts at time , then it executes units of time and reaches the end of time .
Now function calls function , function starts at time , executes units of time and end at time .
Function is running again at time , and also end at the time , thus executes unit of time.
So function totally execute + = units of time, and function totally execute units of time.
Note:
Input logs will be sorted by timestamp, NOT log id.
Your output should be sorted by function id, which means the 0th element of your output corresponds to the exclusive time of function .
Two functions won't start or end at the same time.
Functions could be called recursively, and will always end.
<= n <=
一刷没有想清楚怎么将中间退栈时得到的中间时间段存下来WA。二刷使用大神的算法,和我的算法相似,但是使用了stringstream,并且自己设计了新的struct,效率可能会受影响,但是非常清晰。中间没对stack判空RE。再刷。
class Solution { public:
struct Log {
int id;
string status;
int t;
};
vector<int> exclusiveTime(int n, vector<string>& logs) {
vector<int> res(n, );
stack<Log> s;
for (string str : logs) {
stringstream ss(str);
string t1, t2, t3;
getline(ss, t1, ':');
getline(ss, t2, ':');
getline(ss, t3, ':');
Log log = {stoi(t1), t2, stoi(t3)};
if (log.status == "start") {
s.push(log);
} else {
if (s.top().id == log.id) {
int time = log.t - s.top().t + ;
res[log.id] += time;
s.pop();
if (!s.empty() && s.top().status == "start") {
res[s.top().id] -= time;
}
}
}
}
return res;
}
};
215. Kth Largest Element in an Array
https://leetcode.com/problems/kth-largest-element-in-an-array/description/
Find the kth largest element in an unsorted array. Note that it is the kth largest element in the sorted order, not the kth distinct element. For example,
Given [,,,,,] and k = , return . Note:
You may assume k is always valid, ≤ k ≤ array's length.
一刷使用快排AC,快排的partition函数不止可以用挖坑填坑的方式写,还可以按照这个算法写,但是有bug,再刷!
class Solution {
private:
int partition(vector<int>& s, int l, int r) {
int i = l + , j = r, x = s[l];
while (i <= j) {
if (s[i] < x && s[j] > x) {
swap(s[i++], s[j--]);
}
if (s[i] >= x) {
i++;
}
if (s[j] <= x) {
j--;
}
}
swap(s[l], s[j]);
return j;
}
public:
int findKthLargest(vector<int>& nums, int k) {
int l = , r = nums.size() - ;
while () {
int pos = partition(nums, l, r);
if (pos == k - ) {
return nums[pos];
}
if (pos < k -) {
l = pos + ;
} else {
r = pos - ;
}
}
}
};
347. Top K Frequent Elements
https://leetcode.com/problems/top-k-frequent-elements/description/
Given a non-empty array of integers, return the k most frequent elements. For example,
Given [,,,,,] and k = , return [,]. Note:
You may assume k is always valid, ≤ k ≤ number of unique elements.
Your algorithm's time complexity must be better than O(n log n), where n is the array's size.
一刷使用map统计频率,按频率倒排,使用lambda表达式简化代码,O(NlogN)。二刷使用堆排,O(NlogN)。三刷使用快搜,O(N)。四刷使用priority_queue,O(NlogN),其实就是完全堆排。五刷简化四刷使用的方法,不再使用函数对象。五刷使用桶排序方式,O(N)。
class Solution {
public:
vector<int> topKFrequent(vector<int>& nums, int k) {
map<int, int> m;
for (int n : nums) m[n]++;
vector<pair<int, int>> v(m.begin(), m.end());
sort(v.begin(), v.end(), [] (const pair<int, int>& a, const pair<int, int>& b) {return a.second > b.second;});
vector<int> res;
for (int i = ; i < k; i++) res.push_back(v[i].first);
return res;
}
};
brute_force
class Solution {
public:
map<int, int> m;
vector<int> topKFrequent(vector<int>& nums, int k) {
for (int n : nums) m[n]++;
vector<int> v, res;
for (auto p : m) v.push_back(p.first);
int n = v.size();
for (int i = n / - ; i >= ; i--) max_heapify(v, i, n);
for (int i = n - ; i >= && k--; i--) {
res.push_back(v[]);
swap(v[i], v[]);
max_heapify(v, , i);
}
return res;
}
void max_heapify(vector<int>& v, int b, int e) {
int cur = b, child = * b + ;
while (child < e) {
if (child + < e && m[v[child]] < m[v[child + ]]) child++;
if (m[v[cur]] < m[v[child]]) {
swap(v[cur], v[child]);
cur = child;
child = child * + ;
} else break;
}
}
};
heap_sort
class Solution {
public:
map<int, int> m;
vector<int> topKFrequent(vector<int>& nums, int k) {
for (auto n: nums) m[n]++;
vector<int> s;
for (auto p : m) s.push_back(p.first);
int l = s.size(), b = , e = l - , pos;
while () {
pos = partition(s, b, e);
if (pos == l - k) return vector<int>(s.begin() + l - k, s.end());
else if (pos < l - k) b = pos + ;
else e = pos - ;
}
}
int partition(vector<int>& s, int b, int e) {
int l = b, r = e, x = s[l];
while (l < r) {
while (l < r && m[s[r]] >= m[x]) r--;
if (l < r) s[l++] = s[r];
while (l < r && m[s[l]] <= m[x]) l++;
if (l < r) s[r--] = s[l];
}
s[l] = x;
return l;
}
};
quick_search
class Solution {
public:
vector<int> topKFrequent(vector<int>& nums, int k) {
map<int, int> m;
for (int n : nums) m[n]++;
priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> q;
for (auto p : m) {
q.push({p.second, p.first});
while (q.size() > k) q.pop();
}
vector<int> res;
while (k--) {
res.push_back(q.top().second);
q.pop();
}
return res;
}
};
priority_queue
class Solution {
public:
vector<int> topKFrequent(vector<int>& nums, int k) {
map<int, int> m;
for (int n : nums) m[n]++;
int n = nums.size();
map<int, vector<int>> freq;
for (auto p : m) {
if (freq.find(p.second) == freq.end()) freq[p.second] = vector<int>(, p.first);
else freq[p.second].push_back(p.first);
}
vector<int> res;
for (int i = n; i > && res.size() < k; i--) {
if (freq.find(i) != freq.end() && freq[i].size() > ) {
for (int j = ; j < freq[i].size() && res.size() < k; j++) res.push_back(freq[i][j]);
}
}
return res;
}
};
bucket_sort
692. Top K Frequent Words
https://leetcode.com/problems/top-k-frequent-words/description/
Given a non-empty list of words, return the k most frequent elements. Your answer should be sorted by frequency from highest to lowest. If two words have the same frequency, then the word with the lower alphabetical order comes first. Example :
Input: ["i", "love", "leetcode", "i", "love", "coding"], k =
Output: ["i", "love"]
Explanation: "i" and "love" are the two most frequent words.
Note that "i" comes before "love" due to a lower alphabetical order.
Example :
Input: ["the", "day", "is", "sunny", "the", "the", "the", "sunny", "is", "is"], k =
Output: ["the", "is", "sunny", "day"]
Explanation: "the", "is", "sunny" and "day" are the four most frequent words,
with the number of occurrence being , , and respectively.
Note:
You may assume k is always valid, ≤ k ≤ number of unique elements.
Input words contain only lowercase letters.
Follow up:
Try to solve it in O(n log k) time and O(n) extra space.
Can you solve it in O(n) time with only O(k) extra space?
一刷暴力解决,AC。二刷使用基于heap sort的方法,WA。有一点不太理解,为什么最后的结果的顺序和我想的相反?还有继续优化的空间!
class Solution {
private:
unordered_map<string, int> m;
void max_heapify(vector<string>& s, int b, int e) {
int cur = b, child = * b + ;
while (child < e) {
if (child + < e && (m[s[child]] < m[s[child + ]] || (m[s[child]] == m[s[child + ]] && s[child] > s[child + ]))){
child++;
}
if (m[s[cur]] < m[s[child]] || (m[s[child]] == m[s[cur]] && s[cur] > s[child])) {
swap(s[cur], s[child]);
cur = child;
child = child * + ;
} else {
break;
}
}
} public:
vector<string> topKFrequent(vector<string>& words, int k) {
for (auto word : words) {
m[word]++;
}
vector<string> v;
for (auto p : m) {
v.push_back(p.first);
}
int s = v.size();
for (int i = s / - ; i >= ; i--) {
max_heapify(v, i, s);
}
vector<string> res;
for (int i = s - ; i >= s - k; i--) {
swap(v[i], v[]);
res.push_back(v[i]);
max_heapify(v, , i);
}
return res;
}
};
heap
class Solution {
public:
static bool myCompare(pair<string, int> p1, pair<string, int> p2) {
return (p1.second > p2.second) || (p1.second == p2.second && p1.first < p2.first);
}
vector<string> topKFrequent(vector<string>& words, int k) {
unordered_map<string, int> m;
for (string s : words) {
m[s]++;
}
vector<pair<string, int> > v(m.begin(), m.end());
sort(v.begin(), v.end(), myCompare);
vector<string> res;
for (int i = ; i< k; i++) {
res.push_back(v[i].first);
}
return res;
}
};
brute force
355. Design Twitter
https://leetcode.com/problems/design-twitter/description/
Design a simplified version of Twitter where users can post tweets, follow/unfollow another user and is able to see the most recent tweets in the user's news feed. Your design should support the following methods: postTweet(userId, tweetId): Compose a new tweet.
getNewsFeed(userId): Retrieve the most recent tweet ids in the user's news feed. Each item in the news feed must be posted by users who the user followed or by the user herself. Tweets must be ordered from most recent to least recent.
follow(followerId, followeeId): Follower follows a followee.
unfollow(followerId, followeeId): Follower unfollows a followee.
Example: Twitter twitter = new Twitter(); // User 1 posts a new tweet (id = 5).
twitter.postTweet(, ); // User 1's news feed should return a list with 1 tweet id -> [5].
twitter.getNewsFeed(); // User 1 follows user 2.
twitter.follow(, ); // User 2 posts a new tweet (id = 6).
twitter.postTweet(, ); // User 1's news feed should return a list with 2 tweet ids -> [6, 5].
// Tweet id 6 should precede tweet id 5 because it is posted after tweet id 5.
twitter.getNewsFeed(); // User 1 unfollows user 2.
twitter.unfollow(, ); // User 1's news feed should return a list with 1 tweet id -> [5],
// since user 1 is no longer following user 2.
twitter.getNewsFeed();
一刷使用基于堆排序的方法AC,效率并不是很高。明白了为什么有时候会和结果反序,这是因为我写的堆排序的结果是升序,而这种题目一般要求要降序输出结果。
class Twitter {
private:
unordered_map<int, vector<int> > u2p;
unordered_map<int, unordered_set<int> > r2e;
unordered_map<int, int> id2i;
int total_post;
void max_heapify(vector<int>& s, int b, int e) {
int cur = b, child = * b + ;
while (child < e) {
if (child + < e && (id2i[s[child]] < id2i[s[child + ]])) {
child++;
}
if (id2i[s[cur]] < id2i[s[child]]) {
swap(s[cur], s[child]);
cur = child;
child = * child + ;
} else {
break;
}
}
}
public:
/** Initialize your data structure here. */
Twitter() {
total_post = ;
} /** Compose a new tweet. */
void postTweet(int userId, int tweetId) {
if (u2p.find(userId) == u2p.end()) {
u2p[userId] = vector<int> (, tweetId);
} else {
u2p[userId].push_back(tweetId);
}
total_post++;
id2i[tweetId] = total_post;
} /** Retrieve the 10 most recent tweet ids in the user's news feed. Each item in the news feed must be posted by users who the user followed or by the user herself. Tweets must be ordered from most recent to least recent. */
vector<int> getNewsFeed(int userId) {
vector<int> posts(u2p[userId].begin(), u2p[userId].end());
for (int u : r2e[userId]) {
for (int p : u2p[u]) {
posts.push_back(p);
}
}
int s = posts.size();
for (int i = s / ; i >= ; i--) {
max_heapify(posts, i, s);
}
vector<int> res;
for (int i = s - ; i >= && i >= s - ; i--) {
swap(posts[i], posts[]);
res.push_back(posts[i]);
max_heapify(posts, , i);
}
return res;
} /** Follower follows a followee. If the operation is invalid, it should be a no-op. */
void follow(int followerId, int followeeId) {
if (followerId == followeeId) {
return;
}
if (r2e.find(followerId) == r2e.end()) {
r2e[followerId] = unordered_set<int> ();
}
r2e[followerId].insert(followeeId);
} /** Follower unfollows a followee. If the operation is invalid, it should be a no-op. */
void unfollow(int followerId, int followeeId) {
if (followerId == followeeId) {
return;
}
r2e[followerId].erase(followeeId);
}
}; /**
* Your Twitter object will be instantiated and called as such:
* Twitter obj = new Twitter();
* obj.postTweet(userId,tweetId);
* vector<int> param_2 = obj.getNewsFeed(userId);
* obj.follow(followerId,followeeId);
* obj.unfollow(followerId,followeeId);
*/
heap
490. Maze
锁定了,写不了。
Maze
Given a maze and a start point and a target point, return whether the target can be reached.
Example Input:
Start Point: (, ); Target Point (, ); Maze: char[][] = {
{'.', 'X', '.', '.', '.', 'X'}, {'.', '.', '.', 'X', '.', 'X'}, {'X', 'X', '.', 'X', '.', '.'}, {'.', 'X', 'X', 'X', '.', 'X'}, {'.', '.', '.', '.', '.', 'X'}, {'.', '.', '.', '.', '.', '.'}
}
Example Output: True
但是比较简单,至少有两种写法。
可以采用java的方法写。
110. Balanced Binary Tree
https://leetcode.com/problems/balanced-binary-tree/description/
Given a binary tree, determine if it is height-balanced. For this problem, a height-balanced binary tree is defined as a binary tree in which the depth of the two subtrees of every node never differ by more than .
dfs。一种优化可以使用memo避开一些重复计算。另一种优化转为计算树的高度的问题,高度为-1表示不平衡,可以实现短路计算。
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
private:
private: unordered_map<TreeNode*, int> m;
int get_depth(TreeNode* root) {
if (!root) {
return ;
}
if (m.find(root) != m.end()) {
return m[root];
}
return m[root] = max(get_depth(root->left), get_depth(root->right)) + ;
}
public:
bool isBalanced(TreeNode* root) {
if (!root) return true;
return isBalanced(root->left) && isBalanced(root->right) && abs(get_depth(root->left) - get_depth(root->right)) < ;
}
};
dfs-with-memo
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
private:
int get_depth(TreeNode* root) {
if (!root) return ;
int left_depth = get_depth(root->left);
int right_depth = get_depth(root->right);
if (left_depth == - || right_depth == - || abs(left_depth - right_depth) > ) {
return -;
}
return max(left_depth, right_depth) + ;
}
public:
bool isBalanced(TreeNode* root) {
return get_depth(root) != -;
}
};
dfs-short-circuit-optimization
373. Find K Pairs with Smallest Sums
https://leetcode.com/problems/find-k-pairs-with-smallest-sums/description/
You are given two integer arrays nums1 and nums2 sorted in ascending order and an integer k. Define a pair (u,v) which consists of one element from the first array and one element from the second array. Find the k pairs (u1,v1),(u2,v2) ...(uk,vk) with the smallest sums. Example :
Given nums1 = [,,], nums2 = [,,], k = Return: [,],[,],[,] The first pairs are returned from the sequence:
[,],[,],[,],[,],[,],[,],[,],[,],[,]
Example :
Given nums1 = [,,], nums2 = [,,], k = Return: [,],[,] The first pairs are returned from the sequence:
[,],[,],[,],[,],[,],[,],[,],[,],[,]
Example :
Given nums1 = [,], nums2 = [], k = Return: [,],[,] All possible pairs are returned from the sequence:
[,],[,]
一刷基于heap来做的,一次AC。效率并不高,要先把所有可能的组合都存下了,然后再用堆排序找出前k个,再刷要注意提升效率。
class Solution {
private:
void max_heapify(vector<pair<int, int> >& s, int b, int e) {
int cur = b, child = * b + ;
while (child < e) {
if (child + < e && s[child].first + s[child].second > s[child + ].first + s[child + ].second) {
child++;
}
if (s[cur].first + s[cur].second > s[child].first + s[child].second) {
swap(s[cur], s[child]);
cur = child;
child = * child + ;
} else {
break;
}
}
}
public:
vector<pair<int, int>> kSmallestPairs(vector<int>& nums1, vector<int>& nums2, int k) {
int s1 = nums1.size(), s2 = nums2.size();
vector<pair<int, int> > s;
for (int n1 : nums1) {
for (int n2 : nums2) {
s.push_back(make_pair(n1, n2));
}
}
int s_size = s.size();
for (int i = s_size / - ; i >= ; i--) {
max_heapify(s, i, s_size);
}
k = min(k, s_size);
vector<pair<int, int>> res;
for (int i = s_size - ; i >= s_size - k; i--) {
swap(s[i], s[]);
res.push_back(s[i]);
max_heapify(s, , i);
}
return res;
}
};
heap
659. Split Array into Consecutive Subsequences
https://leetcode.com/problems/split-array-into-consecutive-subsequences/description/
You are given an integer array sorted in ascending order (may contain duplicates), you need to split them into several subsequences, where each subsequences consist of at least consecutive integers. Return whether you can make such a split. Example :
Input: [,,,,,]
Output: True
Explanation:
You can split them into two consecutive subsequences :
, ,
, ,
Example :
Input: [,,,,,,,]
Output: True
Explanation:
You can split them into two consecutive subsequences :
, , , ,
, ,
Example :
Input: [,,,,,]
Output: False
Note:
The length of the input is in range of [, ]
一刷没思路,找了一个比较容易理解的思路看了半天!一刷没有写temp[i]--,思路效率一般,还要继续理解,再刷!时间和空间复杂度均为O(N)。
class Solution {
public:
bool isPossible(vector<int>& nums) {
unordered_map<int, int> f;
for (int num : nums) {
f[num]++;
}
unordered_map<int, int> tmp;
for (int num: nums) {
if (f[num] == ) continue;
if (tmp[num] > ) {
f[num]--;
tmp[num]--;
tmp[num+]++;
} else if (f[num + ] > && f[num + ] > ) {
f[num]--;
f[num + ]--;
f[num + ]--;
tmp[num + ]++;
} else {
return false;
}
}
return true;
}
};
100. Same Tree
https://leetcode.com/problems/same-tree/description/
Given two binary trees, write a function to check if they are equal or not. Two binary trees are considered equal if they are structurally identical and the nodes have the same value.
递归,一次AC。
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
bool isSameTree(TreeNode* p, TreeNode* q) {
if (p && q) {
return (p->val == q->val) && isSameTree(p->left, q->left) && isSameTree(p->right, q->right);
} else if (p || q) {
return false;
} else {
return true;
}
}
};
98. Validate Binary Search Tree
https://leetcode.com/problems/validate-binary-search-tree/description/
Given a binary tree, determine if it is a valid binary search tree (BST). Assume a BST is defined as follows: The left subtree of a node contains only nodes with keys less than the node's key.
The right subtree of a node contains only nodes with keys greater than the node's key.
Both the left and right subtrees must also be binary search trees.
Example : / \ Binary tree [,,], return true.
Example : / \ Binary tree [,,], return false.
递归使用min和max限定子树范围。非递归利用BST的中序遍历一定是递增序列的性质。
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
private:
bool isValidBST(TreeNode* root, TreeNode* min_node, TreeNode* max_node) {
if (!root) {
return true;
}
if ((min_node && root->val <= min_node->val) || (max_node && root->val >= max_node->val)) {
return false;
}
return isValidBST(root->left, min_node, root) && isValidBST(root->right, root, max_node);
}
public:
bool isValidBST(TreeNode* root) {
return isValidBST(root, NULL, NULL);
}
};
recursion
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
bool isValidBST(TreeNode* root) {
stack<TreeNode*> s;
TreeNode * pre = NULL;
while (root || !s.empty()) {
while (root) {
s.push(root);
root = root->left;
}
root = s.top();
s.pop();
if (pre && pre->val >= root->val) {
return false;
}
pre = root;
root = root->right;
}
return true;
}
};
no recursion
113. Path Sum II
https://leetcode.com/problems/path-sum-ii/description/
Given a binary tree and a sum, find all root-to-leaf paths where each path's sum equals the given sum. For example:
Given the below binary tree and sum = , / \ / / \ / \ / \ return
[
[,,,],
[,,,]
]
dfs。遍历解空间,收集合法解。不用去重,比较简单。
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
vector<vector<int>> pathSum(TreeNode* root, int sum) {
vector<vector<int>> res;
if (!root) return res;
vector<int> path;
dfs(res, path, root, sum);
return res;
}
void dfs(vector<vector<int>>& res, vector<int>& path, TreeNode* root, int sum) {
path.push_back(root->val);
if (root->val == sum && !root->left && !root->right) res.push_back(path);
if (root->left) dfs(res, path, root->left, sum - root->val);
if (root->right) dfs(res, path, root->right, sum - root->val);
path.pop_back();
}
};
dfs
124. Binary Tree Maximum Path Sum
https://leetcode.com/problems/binary-tree-maximum-path-sum/description/
Given a binary tree, find the maximum path sum. For this problem, a path is defined as any sequence of nodes from some starting node to any node in the tree along the parent-child connections. The path must contain at least one node and does not need to go through the root. For example:
Given the below binary tree, / \ Return .
dfs。一种方法是两个递归,小的递归找出以root为起点以任意节点为终点的所有path sum的最大值,大的递归找出以任意节点为root的子树的最大path sum作为结果;就是说遍历解空间,大递归遍历以任意节点为根的子树,对子树调用小递归,更新大递归的解。以这种方法存在大量的重复计算,效率低。
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
int maxPathSum(TreeNode* root) {
int res = INT_MIN;
maxPathSum(root, res);
return res;
}
void maxPathSum(TreeNode *root, int &res) {
if (!root) return;
int l = root->val, r = l, s = l;
if (root->left) {
int t = INT_MIN;
maxSidePathSum(root->left, , t);
s += t; l += t;
}
if (root->right) {
int t = INT_MIN;
maxSidePathSum(root->right, , t);
s += t; r += t;
}
res = max(res, max(root->val, max(s, max(l, r))));
maxPathSum(root->left, res);
maxPathSum(root->right, res);
}
void maxSidePathSum(TreeNode *root, int sum, int& res) {
sum += root->val; res = max(res, sum);
if (root->left) maxSidePathSum(root->left, sum, res);
if (root->right) maxSidePathSum(root->right, sum, res);
}
};
另一种方法将大递归和小递归融合成一个递归,在小递归中更新全局最优解,但是返回小递归的解。
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
int maxPathSum(TreeNode* root) {
int res = INT_MIN;
solve(root, res);
return res;
}
int solve(TreeNode *root, int& res) {
if (!root) return ;
int left = max(, solve(root->left, res)), right = max(, solve(root->right, res));
res = max(res, left + right + root->val);
return max(left, right) + root->val;
}
};
200. Number of Islands
https://leetcode.com/problems/number-of-islands/description/
Given a 2d grid map of ''s (land) and ''s (water), count the number of islands. An island is surrounded by water and is formed by connecting adjacent lands horizontally or vertically. You may assume all four edges of the grid are all surrounded by water. Example : Answer: Example : Answer:
一刷递归没AC,小错误不断,再来一次。效率不高,再想想怎么提高效率。
class Solution {
private:
int idx[] = {, , -, , }, m, n;
void dfs(int i, int j, vector<vector<char>>& grid) {
grid[i][j] = ;
for (int k = ; k < ; k++) {
int new_i = i + idx[k], new_j = j + idx[k + ];
if (new_i >= && new_i < m && new_j >= && new_j < n && grid[new_i][new_j] == '') {
dfs(new_i, new_j, grid);
}
}
}
public:
int numIslands(vector<vector<char>>& grid) {
m = grid.size();
if (m == ) return ;
n = grid[].size();
int res = ;
for (int i = ; i < m; i++) {
for (int j = ; j < n; j++) {
if (grid[i][j] == '') {
dfs(i, j, grid);
res++;
} }
}
return res;
}
};
recursion
473. Matchsticks to Square
https://leetcode.com/problems/matchsticks-to-square/description/
Remember the story of Little Match Girl? By now, you know exactly what matchsticks the little match girl has, please find out a way you can make one square by using up all those matchsticks. You should not break any stick, but you can link them up, and each matchstick must be used exactly one time. Your input will be several matchsticks the girl has, represented with their stick length. Your output will either be true or false, to represent whether you could make one square using all the matchsticks the little match girl has. Example :
Input: [,,,,]
Output: true Explanation: You can form a square with length , one side of the square came two sticks with length .
Example :
Input: [,,,,]
Output: false Explanation: You cannot find a way to form a square with all the matchsticks.
Note:
The length sum of the given matchsticks is in the range of to ^.
The length of the given matchstick array will not exceed .
一刷递归,效率低,有大量重复计算,因为边长的组合是具有等价性!这应该是一个set,而不是一个list!自己的逻辑不清晰,TLE。二刷发现大神的DFS思路和我一致,按照大神的思路改完之后效率提高很多,但是仍然有优化的空间,重复计算问题并没有完全解决。
class Solution {
private:
bool dfs(vector<int>& nums, int start, vector<int>& edges, int limit) {
if (start == nums.size()) {
if (edges[] == limit && edges[] == limit && edges[] == limit) {
return true;
} else {
return false;
}
}
for (int k = ; k < ; k++) {
if (edges[k] + nums[start] > limit) continue;
edges[k] += nums[start];
if (dfs(nums, start + , edges, limit)) {
return true;
}
edges[k] -= nums[start];
}
return false;
} public:
static bool myCompare(int a, int b) {
return a > b;
} bool makesquare(vector<int>& nums) {
int edge_len = , cir = ;
for (int n : nums) {
cir += n;
}
if (!cir || cir % != ) {
return false;
}
sort(nums.begin(), nums.end(), myCompare);
edge_len = cir / ;
vector<int> edges(, );
return dfs(nums, , edges, edge_len);
}
};
dfs
51. N-Queens
https://leetcode.com/problems/n-queens/description/
The n-queens puzzle is the problem of placing n queens on an n×n chessboard such that no two queens attack each other. Given an integer n, return all distinct solutions to the n-queens puzzle. Each solution contains a distinct board configuration of the n-queens' placement, where 'Q' and '.' both indicate a queen and an empty space respectively. For example,
There exist two distinct solutions to the -queens puzzle: [
[".Q..", // Solution 1
"...Q",
"Q...",
"..Q."], ["..Q.", // Solution 2
"Q...",
"...Q",
".Q.."]
]
dfs时让col递增,逐个选择合法的row,存储path,path的含义是(path[i], i)位置可以放一个Queen,之后将合法path转为棋局排列。注意判断冲突有三个条件(1)row1 != row2(2)row1 + col1 != row2 + col2 (3)row1 - col1 != row2 - col2。
class Solution {
public:
vector<vector<string>> solveNQueens(int n) {
vector<vector<string>> res;
vector<int> path;
dfs(n, res, path, );
return res;
}
void dfs(int n, vector<vector<string>>& res, vector<int>& path, int col) {
if (col == n) {
vector<string> tmp(n, string(n, '.'));
for (int i = ; i < n; i++) tmp[i][path[i]] = 'Q';
res.push_back(tmp);
}
for (int r = ; r < n; r++) {
if (!conflict(path, r, col)) {
path.push_back(r);
dfs(n, res, path, col + );
path.pop_back();
}
}
} bool conflict(const vector<int>& path, int row, int col) {
for (int i = ; i < path.size(); i++) {
if (path[i] == row || i + path[i] == col + row || row - col == path[i] - i) return true;
}
return false;
}
};
52. N-Queens II
https://leetcode.com/problems/n-queens-ii/description/
Follow up for N-Queens problem. Now, instead outputting board configurations, return the total number of distinct solutions.
dfs,思路同上。
class Solution {
public:
int totalNQueens(int n) {
int res = ;
vector<int> path;
dfs(res, n, path, );
return res;
}
void dfs(int& res, int n, vector<int>& path, int col) {
if (col == n) res+= ;
for (int r = ; r < n; r++) {
if (!conflict(path, r, col)) {
path.push_back(r);
dfs(res, n, path, col + );
path.pop_back();
}
}
}
bool conflict(const vector<int>& path, int row, int col) {
for (int i = ; i < path.size(); i++) if (path[i] == row || i - path[i] == col - row || i + path[i] == row + col) return true;
return false;
}
};
36. Valid Sudoku
https://leetcode.com/problems/valid-sudoku/description/
暴力法:检查行 检查列 检查每个小矩阵就行,这种方法要遍历board3次。
class Solution {
public:
bool isValidSudoku(vector<vector<char>>& board) {
vector<int> nums;
for (int i = ; i < ; i++) {
nums.clear(); nums.resize(, );
for (int j = ; j < ; j++) {
if (board[i][j] != '.') {
if (nums[board[i][j] - ''] > ) return false;
nums[board[i][j] - '']++;
}
}
}
for (int j = ; j < ; j++) {
nums.clear(); nums.resize(, );
for (int i = ; i < ; i++) {
if (board[i][j] != '.') {
if (nums[board[i][j] - ''] > ) return false;
nums[board[i][j] - '']++;
}
}
}
for (int i = ; i < ; i++) {
for (int j = ; j < ; j++) {
nums.clear(); nums.resize(, );
for (int k = ; k < ; k++) {
int i_bias = k / , j_bias = k % ;
if (board[i * + i_bias][j * + j_bias] != '.') {
if (nums[board[i * + i_bias][j * + j_bias] - ''] > ) return false;
nums[board[i * + i_bias][j * + j_bias] - '']++;
}
}
}
}
return true;
}
};
brute_force
更巧妙的方法:记录每行、每列、每个小方块中每个数字是否使用过,如果使用过了,就是invalid,这种方法只需遍历1次board。学习数组的初始化,dp可以有更简单的写法了!
class Solution {
public:
bool isValidSudoku(vector<vector<char>>& board) {
int row_used[][] = {}, col_used[][] = {}, box_used[][] = {};
for (int i = ; i < ; i++) {
for (int j = ; j < ; j++) {
if (board[i][j] != '.') {
int num = board[i][j] - '', k = i / * + j / ;
if (row_used[i][num] || col_used[j][num] || box_used[k][num]) return false;
row_used[i][num] = col_used[j][num] = box_used[k][num] = ;
}
}
}
return true;
}
};
effective
37. Sudoku Solver
https://leetcode.com/problems/sudoku-solver/description/
Write a program to solve a Sudoku puzzle by filling the empty cells. Empty cells are indicated by the character '.'. You may assume that there will be only one unique solution. A sudoku puzzle... ...and its solution numbers marked in red.
一刷使用DFS能AC,不太理解后2个return值设置的含义。
class Solution {
private:
bool solve(vector<vector<char>>& board) {
for (int i = ; i < ; i++) {
for (int j = ; j < ; j++) {
if (board[i][j] == '.') {
for (char c = ''; c <= ''; c++) {
if (valid(board, i, j, c)) {
board[i][j] = c;
if (solve(board)) {
return true;
} else {
board[i][j] = '.';
}
}
}
return false;
}
}
}
return true;
} bool valid(vector<vector<char>>& board, int row, int col, char c) {
for (int i = ; i < ; i++) {
// 检查同行的每一个元素
if (board[row][i] == c && board[row][i] != '.') return false;
// 检查同列的每一个元素
if (board[i][col] == c && board[i][col] != '.') return false;
// 检查同一小方格中的每一个元素
if (c == board[(row / ) * + i / ][(col / ) * + i % ] && board[(row / ) * + i/ ][(col / ) * + i % ] != '.') return false;
}
return true;
}
public:
void solveSudoku(vector<vector<char>>& board) {
if (board.size() == || board[].size() == ) return;
solve(board);
} };
102. Binary Tree Level Order Traversal
https://leetcode.com/problems/binary-tree-level-order-traversal/description/
双queue实现bfs,注意layer数组收集的是本层元素而不是后一层的元素。
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
vector<vector<int>> levelOrder(TreeNode* root) {
vector<vector<int>> res;
if (!root) return res;
queue<TreeNode*> q, next;
q.push(root);
vector<int> layer;
while (!q.empty()) {
while (!q.empty()) {
auto cur = q.front();
layer.push_back(cur->val);
q.pop();
if (cur->left) next.push(cur->left);
if (cur->right) next.push(cur->right);
}
swap(q, next);
res.push_back(layer);
layer.resize();
}
return res;
}
};
bfs
127. Word Ladder
https://leetcode.com/problems/word-ladder/description/
Given two words (beginWord and endWord), and a dictionary's word list, find the length of shortest transformation sequence from beginWord to endWord, such that: Only one letter can be changed at a time.
Each transformed word must exist in the word list. Note that beginWord is not a transformed word.
For example, Given:
beginWord = "hit"
endWord = "cog"
wordList = ["hot","dot","dog","lot","log","cog"]
As one shortest transformation is "hit" -> "hot" -> "dot" -> "dog" -> "cog",
return its length . Note:
Return if there is no such transformation sequence.
All words have the same length.
All words contain only lowercase alphabetic characters.
You may assume no duplicates in the word list.
You may assume beginWord and endWord are non-empty and are not the same.
UPDATE (//):
The wordList parameter had been changed to a list of strings (instead of a set of strings). Please reload the code definition to get the latest changes.
双queue实现BFS。
class Solution {
public:
int ladderLength(string beginWord, string endWord, vector<string>& wordList) {
unordered_map<string, bool> visit;
for (string word : wordList) visit[word] = false;
queue<string> q, next;
q.push(beginWord);
int dis = ;
while (!q.empty()) {
while (!q.empty()) {
string cur = q.front();
q.pop();
for (int i = ; i < cur.size(); i++) {
char tmp = cur[i];
for (char c = 'a'; c <= 'z'; c++) {
if (c == tmp) continue;
cur[i] = c;
if (visit.find(cur) != visit.end() && !visit[cur]) {
if (cur == endWord) return dis + ;
next.push(cur);
visit[cur] = true;
}
cur[i] = tmp;
}
}
}
swap(q, next);
dis++;
}
return ;
}
};
bfs
515. Find Largest Value in Each Tree Row
https://leetcode.com/problems/find-largest-value-in-each-tree-row/description/
You need to find the largest value in each row of a binary tree. Example:
Input: / \ / \ \ Output: [, , ]
BFS,一刷AC。
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
vector<int> largestValues(TreeNode* root) {
vector<int> res;
if (!root) return res;
queue<TreeNode*> q;
q.push(root);
int local_max = INT_MIN, last_level = ;
while (!q.empty()) {
auto cur = q.front();
q.pop();
last_level--;
local_max = max(local_max, cur->val);
if (cur->left) q.push(cur->left);
if (cur->right) q.push(cur->right);
if (last_level == ) {
res.push_back(local_max);
local_max = INT_MIN;
last_level = q.size();
}
}
return res;
}
};
bfs
199. Binary Tree Right Side View
https://leetcode.com/problems/binary-tree-right-side-view/description/
Given a binary tree, imagine yourself standing on the right side of it, return the values of the nodes you can see ordered from top to bottom. For example:
Given the following binary tree,
<---
/ \
<---
\ \
<---
You should return [, , ].
BFS,一刷AC。
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
vector<int> rightSideView(TreeNode* root) {
vector<int> res;
if (!root) return res;
queue<TreeNode*> q;
q.push(root);
int last_level = ;
while (!q.empty()) {
auto cur = q.front();
q.pop();
last_level--;
if (cur->left) q.push(cur->left);
if (cur->right) q.push(cur->right);
if (last_level == ) {
res.push_back(cur->val);
last_level = q.size();
}
}
return res;
}
};
bfs
130. Surrounded Regions
https://leetcode.com/problems/surrounded-regions/description/
Given a 2D board containing 'X' and 'O' (the letter O), capture all regions surrounded by 'X'. A region is captured by flipping all 'O's into 'X's in that surrounded region. For example,
X X X X
X O O X
X X O X
X O X X
After running your function, the board should be: X X X X
X X X X
X X X X
X O X X
有点小弯,不能从所有单元出发进行dfs或者bfs,只要从四条边界出发使用dfs或者bfs即可。一刷dfs,AC。二刷使用bfs,cpp代码mle,java代码tle。
class Solution {
private int m, n;
private int[] bias = {1, 0, -1, 0, 1};
private void bfs(char[][] board, int i, int j) {
if (board[i][j] != 'O') return;
Queue<Integer> q = new LinkedList<>();
q.offer(i * n + j);
while (!q.isEmpty()) {
int p = q.poll();
board[p / n][p % n] = 'F';
for (int k = 0; k < 4; k++) {
int nx = p / n + bias[k], ny = p % n + bias[k + 1];
if (nx >= 0 && nx < m && ny >= 0 && ny < n && board[nx][ny] == 'O') {
q.offer(nx * n + ny);
}
}
} }
public void solve(char[][] board) {
if (board.length == 0 || board[0].length == 0) return;
m = board.length;
n = board[0].length;
for (int i = 0; i < m; i++) {
bfs(board, i, 0);
bfs(board, i, n - 1);
}
for (int j = 0; j < n; j++) {
bfs(board, 0, j);
bfs(board, m - 1, j);
}
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
board[i][j] = (board[i][j] == 'F' ? 'O' : 'X');
}
}
}
}
bfs
class Solution {
private:
int m, n;
int bias[] = {, , -, , };
void bfs(vector<vector<char>>& board, int i, int j) {
if (i < || i >= m || j < || j >= n || board[i][j] != 'O') return;
queue<pair<int, int>> q;
q.push(make_pair(i, j));
while (!q.empty()) {
auto p = q.front();
q.pop();
int x = p.first, y = p.second;
board[x][y] = 'F';
for (int k = ; k < ; k++) {
int new_x = x + bias[k], new_y = y + bias[k + ];
if (new_x >= && new_x < m && new_y >= && new_y < n && board[new_x][new_y] == 'O') {
q.push(make_pair(new_x, new_y));
}
}
} }
public:
void solve(vector<vector<char>>& board) {
if (board.size() == || board[].size() == ) return;
m = board.size(), n = board[].size();
for (int i = ; i < m; i++) {
bfs(board, i, );
bfs(board, i, n - );
}
for (int j = ; j < n; j++) {
bfs(board, , j);
bfs(board, m - , j);
}
for (int i = ; i < m; i++) {
for (int j = ; j < n; j++) {
board[i][j] = (board[i][j] == 'F' ? 'O' : 'X');
}
}
}
};
bfs-cpp
class Solution {
private:
int m, n;
int bias[] = {, , -, , };
void dfs(vector<vector<char>>& board, int i, int j) {
if (i < || i >= m || j < || j >= n || board[i][j] != 'O') return;
board[i][j] = 'F';
for (int k = ; k < ; k++) {
dfs(board, i + bias[k], j + bias[k + ]);
}
}
public:
void solve(vector<vector<char>>& board) {
if (board.size() == || board[].size() == ) return;
m = board.size(), n = board[].size();
for (int i = ; i < m; i++) {
dfs(board, i, );
dfs(board, i, n - );
}
for (int j = ; j < n; j++) {
dfs(board, , j);
dfs(board, m - , j);
}
for (int i = ; i < m; i++) {
for (int j = ; j < n; j++) {
board[i][j] = (board[i][j] == 'F' ? 'O' : 'X');
}
}
}
};
dfs
301. Remove Invalid Parentheses
https://leetcode.com/problems/remove-invalid-parentheses/description/
Remove the minimum number of invalid parentheses in order to make the input string valid. Return all possible results. Note: The input string may contain letters other than the parentheses ( and ). Examples:
"()())()" -> ["()()()", "(())()"]
"(a)())()" -> ["(a)()()", "(a())()"]
")(" -> [""]
一刷使用DFS,注意从左向右走,分三种情况考虑,左括号,右括号和字母。二刷使用BFS,没有更新max导致WA。
class Solution {
public List<String> removeInvalidParentheses(String s) {
List<String> res = new ArrayList<>();
int max = 0;
Set<String> checked = new HashSet<>();
Queue<String> q = new LinkedList<>();
boolean found = false;
q.offer(s);
while (!q.isEmpty()) {
String cur = q.poll();
if (isValid(cur)) {
found = true;
if (cur.length() >= max && !res.contains(cur)) {
max = cur.length();
res.add(cur);
}
}
if (found) continue;
for (int i = 0; i < cur.length(); i++) {
String sub1 = cur.substring(0, i);
String sub2 = cur.substring(i + 1, cur.length());
String next = sub1.concat(sub2);
if (!checked.contains(next)) {
q.offer(next);
checked.add(next);
}
}
}
return res; } private boolean isValid(String s) {
int count = 0;
for (int i = 0; i < s.length(); i++) {
if (s.charAt(i) == '(') count++;
else if (s.charAt(i) == ')') {
if (count == 0) return false;
count--;
}
}
return count == 0;
}
}
bfs
class Solution {
public List<String> removeInvalidParentheses(String s) {
dfs(s, "", 0, 0);
if (res.size() == 0) {
res.add("");
}
return res;
} private static void dfs(String str, String subRes, int left, int tmpMax) {
if (str.equals("")) {
if (left == 0 && subRes.length() > 0) {
if (tmpMax > max) {
max = tmpMax;
res.clear();
}
if (tmpMax == max && !res.contains(subRes)) {
res.add(subRes);
}
}
return;
}
if (str.charAt(0) == '(') {
dfs(str.substring(1), subRes.concat("("), left+1, tmpMax + 1);
dfs(str.substring(1), subRes, left, tmpMax);
} else if (str.charAt(0) == ')') {
if (left > 0) {
dfs(str.substring(1), subRes.concat(")"), left - 1, tmpMax + 1);
}
dfs(str.substring(1), subRes, left, tmpMax);
} else {
String skipLetter = String.valueOf(str.charAt(0));
dfs(str.substring(1), subRes.concat(skipLetter), left, tmpMax + 1);
}
} private static List<String> res = new ArrayList<>();
private static int max = 0;
}
dfs
297. Serialize and Deserialize Binary Tree
https://leetcode.com/problems/serialize-and-deserialize-binary-tree/description/
Serialization is the process of converting a data structure or object into a sequence of bits so that it can be stored in a file or memory buffer, or transmitted across a network connection link to be reconstructed later in the same or another computer environment. Design an algorithm to serialize and deserialize a binary tree. There is no restriction on how your serialization/deserialization algorithm should work. You just need to ensure that a binary tree can be serialized to a string and this string can be deserialized to the original tree structure. For example, you may serialize the following tree / \ / \ as "[1,2,3,null,null,4,5]", just the same as how LeetCode OJ serializes a binary tree. You do not necessarily need to follow this format, so please be creative and come up with different approaches yourself.
Note: Do not use class member/global/static variables to store states. Your serialize and deserialize algorithms should be stateless.
一刷使用基于先序遍历的递归方法没AC,没有将val转为string。思路就是先用pre_order遍历,生成字符串,再按pre_order顺序还原二叉树。
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Codec {
private:
int helper(string& data) {
int pos = data.find(',');
string num = data.substr(, pos);
data = data.substr(pos + );
return stoi(num);
} TreeNode* my_deserialize(string& data) {
if (data[] == '#') {
if (data.size() > ) data = data.substr();
return NULL;
}
TreeNode* root = new TreeNode(helper(data));
root->left = my_deserialize(data);
root->right = my_deserialize(data);
return root;
}
public:
// Encodes a tree to a single string.
string serialize(TreeNode* root) {
if (!root) return "#";
return to_string(root->val) + "," + serialize(root->left) + "," + serialize(root->right);
} // Decodes your encoded data to tree.
TreeNode* deserialize(string data) {
return my_deserialize(data);
}
}; // Your Codec object will be instantiated and called as such:
// Codec codec;
// codec.deserialize(codec.serialize(root));
pre_order_recursion
99. Recover Binary Search Tree
https://leetcode.com/problems/recover-binary-search-tree/description/
Two elements of a binary search tree (BST) are swapped by mistake. Recover the tree without changing its structure. Note:
A solution using O(n) space is pretty straight forward. Could you devise a constant space solution?
递归中序遍历。BST的中序遍历结果必定是单调递增的,如果进行替换,一定两次出现前一个比后一个大的情况,第一次出现时,被调换的那个一定是较大的那个,而第二次出现的时候被调换的那个一定是较小的那个。用全局变量first,second,pre分别记录被调换的第一个、第二个、上一次访问的元素,遍历完之后调换first和second节点的val即可。
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
private:
TreeNode *first, *second, *pre;
public:
void recoverTree(TreeNode* root) {
first = NULL, second = NULL, pre = new TreeNode(INT_MIN);
traverse(root);
int tmp = first->val;
first->val = second->val;
second->val = tmp;
}
void traverse(TreeNode *root) {
if (!root) return;
traverse(root->left);
if (!first && pre->val >= root->val) first = pre;
if (first && pre->val >= root->val) second = root;
pre = root;
traverse(root->right);
}
};
recursion
87. Scramble String
https://leetcode.com/problems/scramble-string/description/
Given a string s1, we may represent it as a binary tree by partitioning it to two non-empty substrings recursively. Below is one possible representation of s1 = "great": great
/ \
gr eat
/ \ / \
g r e at
/ \
a t
To scramble the string, we may choose any non-leaf node and swap its two children. For example, if we choose the node "gr" and swap its two children, it produces a scrambled string "rgeat". rgeat
/ \
rg eat
/ \ / \
r g e at
/ \
a t
We say that "rgeat" is a scrambled string of "great". Similarly, if we continue to swap the children of nodes "eat" and "at", it produces a scrambled string "rgtae". rgtae
/ \
rg tae
/ \ / \
r g ta e
/ \
t a
We say that "rgtae" is a scrambled string of "great". Given two strings s1 and s2 of the same length, determine if s2 is a scrambled string of s1.
一刷递归TLE,没有先sort判断字符串是否相同减少递归深度。二刷使用sort之后AC,不是很理解思路。三刷使用java刷AC。四刷使用DP,思路和递归差别不大,边界参数错了好几个,WA。使用if进行短路优化时间比不用短路优化还要长,猜是因为if破坏了流水线结构。
class Solution {
public:
bool isScramble(string s1, string s2) {
if (s1.size() != s2.size()) return false;
if (s1 == s2) return true;
int n = s1.size();
vector<vector<vector<bool>>> dp(n, vector<vector<bool>>(n, vector<bool>(n + , false)));
for (int i = ; i < n; i++) {
for (int j = ; j < n; j++) {
dp[i][j][] = s1[i] == s2[j];
}
}
for (int l = ; l <= n; l++) {
for (int i = ; i < n - l + ; i++) {
for (int j = ; j < n - l + ; j++) {
for (int k = ; k < l; k++) {
dp[i][j][l] = dp[i][j][l] || (dp[i][j][k] && dp[i + k][j + k][l - k]) ||
(dp[i][j + l - k][k] && dp[i + k][j][l - k]);
}
}
}
}
return dp[][][n];
}
};
dp
class Solution {
public:
bool isScramble(string s1, string s2) {
if (s1.size() != s2.size()) return false;
if (s1 == s2) return true;
for (int i = ; i < s1.size(); i++) {
if ((isScramble(s1.substr(, i), s2.substr(, i)) && isScramble(s1.substr(i), s2.substr(i))) ||
(isScramble(s1.substr(, i), s2.substr(s2.size() - i)) && isScramble(s1.substr(s1.size() - i), s2.substr(, i)))) {
return true;
}
}
return false;
}
};
recursion_no_sort_tle
class Solution {
public:
bool isScramble(string s1, string s2) {
if (s1.size() != s2.size()) return false;
if (s1 == s2) return true;
string t1(s1);
string t2(s2);
sort(t1.begin(), t1.end());
sort(t2.begin(), t2.end());
if (t1 != t2) return false;
for (int i = ; i < s1.size(); i++) {
if ((isScramble(s1.substr(, i), s2.substr(, i)) && isScramble(s1.substr(i), s2.substr(i))) ||
(isScramble(s1.substr(, i), s2.substr(s2.size() - i)) && isScramble(s1.substr(i), s2.substr(, s2.size() - i)))) {
return true;
}
}
return false;
}
};
recursion
546. Remove Boxes
https://leetcode.com/problems/remove-boxes/description/
Given several boxes with different colors represented by different positive numbers.
You may experience several rounds to remove boxes until there is no box left. Each time you can choose some continuous boxes with the same color (composed of k boxes, k >= ), remove them and get k*k points.
Find the maximum points you can get. Example :
Input: [, , , , , , , , ]
Output: Explanation:
[, , , , , , , , ]
----> [, , , , , ] (*= points)
----> [, , , , ] (*= points)
----> [, ] (*= points)
----> [] (*= points)
Note: The number of boxes n would not exceed .
一刷递归思路有漏洞,二刷使用DFS,代码看了很久才理解,主要是k参数表示的是起始元素(第i个元素)的重复次数。参数设置出错WA。三刷使用DP参数设置错了好多WA,代码看了好久才明白。l表示的是长度,类似矩阵先填充对角线上的元素,这是理解代码的关键!看了 https://discuss.leetcode.com/topic/84687/java-top-down-and-bottom-up-dp-solutions 链接里的解释,写的非常详细,非常感谢!主要解释了k的作用,非常透彻!
class Solution {
private:
int removeBoxes(vector<int>& boxes, int i, int j, int k, vector<vector<vector<int>>>& tmp) {
if (i > j) return ;
if (tmp[i][j][k] > ) return tmp[i][j][k];
int res = (k + ) * (k + ) + removeBoxes(boxes, i + , j, , tmp);
for (int m = i + ; m <= j; m++) {
if (boxes[m] == boxes[i]) {
res = max(res, removeBoxes(boxes, i + , m - , , tmp) + removeBoxes(boxes, m, j, k + , tmp));
}
}
return tmp[i][j][k] = res;
}
public:
int removeBoxes(vector<int>& boxes) {
int n = boxes.size();
if (n < ) return n;
vector<vector<vector<int>>> tmp(n, vector<vector<int>>(n, vector<int>(n, )));
return removeBoxes(boxes, , n - , , tmp);
}
};
dfs
class Solution {
public:
int removeBoxes(vector<int>& boxes) {
int n = boxes.size();
if (n < ) return n;
vector<vector<vector<int>>> dp(n, vector<vector<int>>(n, vector<int>(n, )));
for (int i = ; i < n; i++) {
for (int k = ; k <= i; k++) {
dp[i][i][k] = (k + ) * (k + );
}
}
for (int l = ; l < n; l++) {
for (int j = l; j < n; j++) {
int i = j - l;
for (int k = ; k <= i; k++) {
int res = (k + ) * (k + ) + dp[i + ][j][];
for (int m = i + ; m <= j; m++) {
if (boxes[m] == boxes[i]) {
res = max(res, dp[i + ][m - ][] + dp[m][j][k + ]);
}
}
dp[i][j][k] = res;
}
}
}
return dp[][n - ][];
}
};
452. Minimum Number of Arrows to Burst Balloons
https://leetcode.com/problems/minimum-number-of-arrows-to-burst-balloons/description/
There are a number of spherical balloons spread in two-dimensional space. For each balloon, provided input is the start and end coordinates of the horizontal diameter. Since it's horizontal, y-coordinates don't matter and hence the x-coordinates of start and end of the diameter suffice. Start is always smaller than end. There will be at most balloons. An arrow can be shot up exactly vertically from different points along the x-axis. A balloon with xstart and xend bursts by an arrow shot at x if xstart ≤ x ≤ xend. There is no limit to the number of arrows that can be shot. An arrow once shot keeps travelling up infinitely. The problem is to find the minimum number of arrows that must be shot to burst all balloons. Example: Input:
[[,], [,], [,], [,]] Output: Explanation:
One way is to shoot one arrow for example at x = (bursting the balloons [,] and [,]) and another arrow at x = (bursting the other two balloons).
贪心算法,自己陷入了一个有多种解需要遍历的怪圈,其实不需要。按终点大小排序后直接从直径终点射出就可以了!再刷!我的思路是每次找到重合最多的坐标点,刺破覆盖该位置的所有气球。重复以上步骤直到气球全部被刺破,这个方法一定奏效,但是复杂度极高。为什么贪心算法能work呢?
class Solution {
private:
static bool myCompare(pair<int, int> a, pair<int, int> b) {
return a.second < b.second;
}
public:
int findMinArrowShots(vector<pair<int, int>>& points) {
int n = points.size();
if (n < ) return n;
sort(points.begin(), points.end(), myCompare);
int res = , arror_pos = points[].second;
for (auto p : points) {
if (p.first <= arror_pos) continue;
res++;
arror_pos = p.second;
}
return res;
}
};
435. Non-overlapping Intervals
https://leetcode.com/problems/non-overlapping-intervals/description/
Given a collection of intervals, find the minimum number of intervals you need to remove to make the rest of the intervals non-overlapping. Note:
You may assume the interval's end point is always bigger than its start point.
Intervals like [,] and [,] have borders "touching" but they don't overlap each other.
Example :
Input: [ [,], [,], [,], [,] ] Output: Explanation: [,] can be removed and the rest of intervals are non-overlapping.
Example :
Input: [ [,], [,], [,] ] Output: Explanation: You need to remove two [,] to make the rest of intervals non-overlapping.
Example :
Input: [ [,], [,] ] Output: Explanation: You don't need to remove any of the intervals since they're already non-overlapping.
与452非常相似,但是并没有想到怎么做,看Wikipedia(https://en.wikipedia.org/wiki/Interval_scheduling#Interval_Scheduling_Maximization)也没看懂,真菜!对于贪心还是不太理解,再刷。
/**
* Definition for an interval.
* struct Interval {
* int start;
* int end;
* Interval() : start(0), end(0) {}
* Interval(int s, int e) : start(s), end(e) {}
* };
*/
class Solution {
private:
static bool myCompare(Interval a, Interval b) {
return a.end < b.end;
}
public:
int eraseOverlapIntervals(vector<Interval>& intervals) {
int n = intervals.size();
if (n < ) return ;
sort(intervals.begin(), intervals.end(), myCompare);
int res = , pos = intervals[].end;
for (auto i : intervals) {
if (i.start >= pos) {
res++;
pos = i.end;
}
}
return n - res;
}
};
621. Task Scheduler
https://leetcode.com/problems/task-scheduler/description/
Given a char array representing tasks CPU need to do. It contains capital letters A to Z where different letters represent different tasks.Tasks could be done without original order. Each task could be done in one interval. For each interval, CPU could finish one task or just be idle. However, there is a non-negative cooling interval n that means between two same tasks, there must be at least n intervals that CPU are doing different tasks or just be idle. You need to return the least number of intervals the CPU will take to finish all the given tasks. Example :
Input: tasks = ["A","A","A","B","B","B"], n =
Output:
Explanation: A -> B -> idle -> A -> B -> idle -> A -> B.
Note:
The number of tasks is in the range [, ].
The integer n is in the range [, ].
一刷没思路,讨论区使用的算法没有看出什么门道,就是找出最频繁的字母,按公式给出结果。公式是:循环体size * 循环次数(频繁字母频率-1) + 剩余的频繁字母个数。公式有特例如3个A,3个B,3个C,1个D,n=2时就不对,此时res=tasks.size()。再刷!
class Solution {
public:
int leastInterval(vector<char>& tasks, int n) {
vector<int> v(, );
for (char c : tasks) {
v[c - 'A']++;
}
sort(v.begin(), v.end());
int i = ;
while (i >= && v[i] == v[]) i--;
int s = tasks.size();
return max(s, (n + ) * (v[] - ) + - i);
}
};
649. Dota2 Senate
https://leetcode.com/problems/dota2-senate/description/
In the world of Dota2, there are two parties: the Radiant and the Dire. The Dota2 senate consists of senators coming from two parties. Now the senate wants to make a decision about a change in the Dota2 game. The voting for this change is a round-based procedure. In each round, each senator can exercise one of the two rights: Ban one senator's right:
A senator can make another senator lose all his rights in this and all the following rounds.
Announce the victory:
If this senator found the senators who still have rights to vote are all from the same party, he can announce the victory and make the decision about the change in the game.
Given a string representing each senator's party belonging. The character 'R' and 'D' represent the Radiant party and the Dire party respectively. Then if there are n senators, the size of the given string will be n. The round-based procedure starts from the first senator to the last senator in the given order. This procedure will last until the end of voting. All the senators who have lost their rights will be skipped during the procedure. Suppose every senator is smart enough and will play the best strategy for his own party, you need to predict which party will finally announce the victory and make the change in the Dota2 game. The output should be Radiant or Dire. Example :
Input: "RD"
Output: "Radiant"
Explanation: The first senator comes from Radiant and he can just ban the next senator's right in the round 1.
And the second senator can't exercise any rights any more since his right has been banned.
And in the round , the first senator can just announce the victory since he is the only guy in the senate who can vote.
Example :
Input: "RDD"
Output: "Dire"
Explanation:
The first senator comes from Radiant and he can just ban the next senator's right in the round 1.
And the second senator can't exercise any rights anymore since his right has been banned.
And the third senator comes from Dire and he can ban the first senator's right in the round 1.
And in the round , the third senator can just announce the victory since he is the only guy in the senate who can vote.
Note:
The length of the given string will in the range [, ,].
一刷使用自己设计的贪心算法,分别使用2个参数(count, skip)为双方计数,WA。总计81个case,卡在第78个。分析发现自己对于题目理解有问题,被ban掉的人没有投票权,拥有投票权的人均属于同一方才算赢,这是一个多轮次的游戏。二刷基于queue对游戏进行模拟,思路是一方将另一方ban掉,靠前的那一方ban,靠后的那一方被ban,而且ban的那一方经过这一轮之后下一轮仍然可以投票,所以要将这个数加上N之后放到队列末尾。二刷AC。
class Solution {
public:
string predictPartyVictory(string senate) {
int n = senate.size();
queue<int> q1, q2;
for (int i = ; i < senate.size(); i++) {
if (senate[i] == 'R') q1.push(i);
else q2.push(i);
}
while (!q1.empty() && !q2.empty()) {
int i1 = q1.front(), i2 = q2.front();
q1.pop();
q2.pop();
if (i1 < i2) q1.push(i1 + n);
else q2.push(i2 + n);
}
return q1.size() > q2.size() ? "Radiant" : "Dire";
}
};
ac
134. Gas Station
https://leetcode.com/problems/gas-station/description/
There are N gas stations along a circular route, where the amount of gas at station i is gas[i]. You have a car with an unlimited gas tank and it costs cost[i] of gas to travel from station i to its next station (i+). You begin the journey with an empty tank at one of the gas stations. Return the starting gas station's index if you can travel around the circuit once, otherwise return -1. Note:
The solution is guaranteed to be unique.
math。做法是遍历i(尝试以i为起点),如果i可以成为起点则返回,如果不能成为起点,则[i, j]中任意一个station都不能成为起点(sum(i,j)<0,对i和j之间的任意一个位置k,sum(i,k)>=0,故l[j]<0, sum[i,j-1]>=0且|l[j]|>sum(i,j-1),故sum(k,j-1)<sum(i,j-1),于是sum(k,j)<0)。直到遍历结束,如果total+tank>0,则一定有解,且start记录的i就是一个解(可以用假设法证明,如果start之后的一个station是解,由于从start可以到达该station,所以start一定也是解。而start之前不可能存在解,如果有解,则start一定是一个解)。
class Solution {
public:
int canCompleteCircuit(vector<int>& gas, vector<int>& cost) {
int start = , tank = , total = ;
// start表示可能成为解的station的index。
// tank表示从start走到i油箱里还有多少油
// total表示从station 0走到station start的剩余油量(<=0)
// total + tank就是总的剩余油量 // 3个关键点
// 1. 如果从i无法走到j,则从i和j之间的任意位置都走不动j
// 2. 如果total + tank >= 0则必有解
// 3. 如果有解,解必为start,因为start之前的station不是解,如果之后的位置是解,由于start可以到达该位置,因此start也是解。
for (int i = ; i < gas.size(); i++) {
if ((tank = tank + gas[i] - cost[i]) < ) {
total += tank; tank = ; start = i + ;
}
}
return total + tank < ? - : start;
}
};
179. Largest Number
https://leetcode.com/problems/largest-number/description/
Given a list of non negative integers, arrange them such that they form the largest number. For example, given [, , , , ], the largest formed number is . Note: The result may be very large, so you need to return a string instead of an integer.
一刷基于sort做,AC。可以直接对数字排序,然后逐个加进来。要更深入地理解为什么这样能work!
class Solution {
private:
static bool myCompare(int a, int b) {
string s1 = to_string(a), s2 = to_string(b);
return s1 + s2 > s2 + s1;
}
public:
string largestNumber(vector<int>& nums) {
int n = nums.size();
if (n == ) return "";
sort(nums.begin(), nums.end(), myCompare);
if (nums[] == ) return "";
string res = "";
for (int num : nums) res += to_string(num);
return res;
}
};
324. Wiggle Sort II
https://leetcode.com/problems/wiggle-sort-ii/description/
Given an unsorted array nums, reorder it such that nums[] < nums[] > nums[] < nums[].... Example:
() Given nums = [, , , , , ], one possible answer is [, , , , , ].
() Given nums = [, , , , , ], one possible answer is [, , , , , ]. Note:
You may assume all input has valid answer. Follow Up:
Can you do it in O(n) time and/or in-place with O() extra space?
一刷使用笨方法,没AC,完全招架不住Follow up。再刷。
class Solution {
public:
void wiggleSort(vector<int>& nums) {
vector<int> tmp(nums);
sort(tmp.begin(), tmp.end());
int n = nums.size();
for (int i = n - , j = , k = i / + ; i >= ; i--) {
nums[i] = tmp[((i & ) ? k++ : j++)];
}
}
};
225. Implement Stack using Queues
https://leetcode.com/problems/implement-stack-using-queues/submissions/
Implement the following operations of a stack using queues. push(x) -- Push element x onto stack.
pop() -- Removes the element on top of the stack.
top() -- Get the top element.
empty() -- Return whether the stack is empty.
Notes:
You must use only standard operations of a queue -- which means only push to back, peek/pop from front, size, and is empty operations are valid.
Depending on your language, queue may not be supported natively. You may simulate a queue by using a list or deque (double-ended queue), as long as you use only standard operations of a queue.
You may assume that all operations are valid (for example, no pop or top operations will be called on an empty stack).
用deque很简单。一刷没AC,pop函数和普通的stack的pop不同,要返回栈顶元素。
class MyStack {
private:
deque<int> s;
public:
/** Initialize your data structure here. */
MyStack() { } /** Push element x onto stack. */
void push(int x) {
s.push_back(x);
} /** Removes the element on top of the stack and returns that element. */
int pop() {
int res = s.back();
s.pop_back();
return res;
} /** Get the top element. */
int top() {
return s.back();
} /** Returns whether the stack is empty. */
bool empty() {
return s.size() == ;
}
}; /**
* Your MyStack object will be instantiated and called as such:
* MyStack obj = new MyStack();
* obj.push(x);
* int param_2 = obj.pop();
* int param_3 = obj.top();
* bool param_4 = obj.empty();
*/
42. Trapping Rain Water
https://leetcode.com/problems/trapping-rain-water/description/
Given n non-negative integers representing an elevation map where the width of each bar is , compute how much water it is able to trap after raining. For example,
Given [,,,,,,,,,,,], return . The above elevation map is represented by array [,,,,,,,,,,,]. In this case, units of rain water (blue section) are being trapped. Thanks Marcos for contributing this image!
stack,递减栈。出栈情况下不用入栈,也不用循环向前将造成递增的元素全部出栈,这样容易理解,但是代码显得过于冗长。
class Solution {
public:
int trap(vector<int>& height) {
stack<int> s;
int n = height.size(), res = , i = ;
while (i < n) {
if (s.empty() || height[i] <= height[s.top()]) s.push(i++);
else {
int bottom = height[s.top()]; s.pop();
res += s.empty() ? : (min(height[s.top()], height[i]) - bottom) * (i - s.top() - );
}
}
return res;
}
};
clean
class Solution {
public:
int trap(vector<int>& height) {
stack<int> s;
int n = height.size(), res = , i = ;
for (int i = ; i < n; i++) {
if (s.empty() || height[i] <= height[s.top()]) s.push(i);
else {
while (!s.empty() && height[i] > height[s.top()]) {
int bottom = height[s.top()]; s.pop();
res += s.empty() ? : (min(height[s.top()], height[i]) - bottom) * (i - s.top() - );
}
s.push(i);
}
}
return res;
}
};
easy_understanding
739. Daily Temperatures
https://leetcode.com/contest/weekly-contest-61/problems/daily-temperatures/
stack,单调栈。注意存的是index,循环用while比较好,更简洁。
class Solution {
public:
vector<int> dailyTemperatures(vector<int>& temperatures) {
int l = temperatures.size(), i = ;
vector<int> res(l);
stack<int> s;
while (i < l) {
if (s.empty() || temperatures[s.top()] >= temperatures[i]) s.push(i++);
else {
int cur = s.top(); s.pop();
res[cur] = i - cur;
}
}
return res;
}
};
84. Largest Rectangle in Histogram
https://leetcode.com/problems/largest-rectangle-in-histogram/description/
Given n non-negative integers representing the histogram's bar height where the width of each bar is 1, find the area of largest rectangle in the histogram. Above is a histogram where width of each bar is , given height = [,,,,,]. The largest rectangle is shown in the shaded area, which has area = unit. For example,
Given heights = [,,,,,],
return .
stack,单调栈。注意要计算的矩形宽度不是(i - 出栈元素的index),而是(i - 出栈后的栈顶 + 1),这么做的原因是因为,当前元素可能是洼地,这么计算就不会少算了。
class Solution {
public:
int largestRectangleArea(vector<int>& heights) {
stack<int> s;
int n = heights.size(), i = , count, res = ;
while (i < n || !s.empty()) {
if (i < n && (s.empty() || heights[i] >= heights[s.top()])) s.push(i++);
else {
int index = s.top(); s.pop();
res = max(res, heights[index] * (s.empty() ? i : (i - s.top() - )));
}
}
return res;
}
};
735. Asteroid Collision
https://leetcode.com/contest/weekly-contest-60/problems/asteroid-collision/
We are given an array asteroids of integers representing asteroids in a row. For each asteroid, the absolute value represents its size, and the sign represents its direction (positive meaning right, negative meaning left). Find out the state of the asteroids after all collisions. If two asteroids meet, the smaller one will explode. If both are the same size, both will explode. Example :
Input:
asteroids = [, , -]
Output: [, ]
Explanation:
The and - collide resulting in . The and never collide.
Example :
Input:
asteroids = [, -]
Output: []
Explanation:
The and - collide exploding each other.
Example :
Input:
asteroids = [, , -]
Output: []
Explanation:
The and - collide resulting in -. The and - collide resulting in .
Note: The length of asteroids will be at most .
Each asteroid will be a non-zero integer in the range [-, ]..
利用stack的特性,注意分类,debug很久!
class Solution {
public:
vector<int> asteroidCollision(vector<int>& asteroids) {
stack<int> s;
if (asteroids.size() == ) return asteroids;
for (int i = ; i < asteroids.size(); i++) {
if (s.empty()) s.push(asteroids[i]);
else {
if (s.top() > && asteroids[i] < ){
while (!s.empty() && s.top() > && asteroids[i] < && abs(s.top()) < abs(asteroids[i])) s.pop();
if (s.empty()) s.push(asteroids[i]);
else {
if (s.top() > ) {
if (abs(s.top()) == abs(asteroids[i])) s.pop();
} else s.push(asteroids[i]);
}
} else {
s.push(asteroids[i]);
}
}
}
vector<int> res;
while (!s.empty()) {
res.push_back(s.top());
s.pop();
}
reverse(res.begin(), res.end());
return res;
}
};
296. Best Meeting Point
A group of two or more people wants to meet and minimize the total travel distance. You are given a 2D grid of values 0 or 1, where each 1 marks the home of someone in the group. The distance is calculated using Manhattan Distance, where distance(p1, p2) = |p2.x - p1.x| + |p2.y - p1.y|.
For example, given three people living at (0,0), (0,4), and (2,2): Result is (0,2)
1-0-0-0-1 ||||| 0-0-0-0-0 |||||
0-0-1-0-0
这是一道锁定题。横轴纵轴互不影响,可以将两个维度直接拆开,每个维度排序之后去掉单个的中间节点,加上剩余配对的节点直接的距离即可。一刷没AC,计算sum的时候横轴和纵轴分到两个循环了,在一个循环就可以了,因为长度都一样,注意end初始应该设为posList.size() - 1。
import java.util.ArrayList;
import java.util.Collections;
import java.util.List; public class BestMeetingPoint {
public static void main(String[] args) {
int[][] grid = {
{1, 0, 0, 0, 1},
{0, 0, 0, 0, 0},
{0, 0, 1, 0, 0}};
System.out.println(minTotalDistance(grid));
} private static int minTotalDistance(int[][] grid) {
List<Integer> iPos = new ArrayList<>();
List<Integer> jPos = new ArrayList<>();
for (int i = 0; i < grid.length; i++) {
for (int j = 0; j < grid[i].length; j++) {
if (grid[i][j] == 1) {
iPos.add(i);
jPos.add(j);
}
}
}
Collections.sort(iPos);
Collections.sort(jPos);
int sum = 0;
int start = 0, end = iPos.size() - 1;
while (start < end) {
sum += iPos.get(end) - iPos.get(start);
sum += jPos.get(end) - jPos.get(start);
end--;
start++;
}
return sum;
}
}
164. Maximum Gap
https://leetcode.com/problems/maximum-gap/description/
Given an unsorted array, find the maximum difference between the successive elements in its sorted form. Try to solve it in linear time/space. Return if the array contains less than elements. You may assume all elements in the array are non-negative integers and fit in the -bit signed integer range.
一刷使用暴力算法,先sort然后遍历,O(NlogN)的时间复杂度。题目要求O(N)的时间和空间复杂度,桶排序可以满足要求。二刷使用桶排序算法,时间和空间复杂度都是O(N)。由于bucket size设置不当(应该再加1),导致运行时出现除零操作RE。bucket size并不是非常重要的参数,bucket的个数也不需要非常严格,但是一定要保证大于等于需要的桶的个数(设为l + 1即可)。
class Solution {
public:
int maximumGap(vector<int>& nums) {
int n = nums.size(), res = ;
if (n < ) return res;
sort(nums.begin(), nums.end());
for (int i = ; i < nums.size(); i++) {
res = max(res, nums[i] - nums[i - ]);
}
return res;
}
};
brute force
class Solution {
public:
int maximumGap(vector<int>& nums) {
int max_elem = INT_MIN, min_elem = INT_MAX, l = nums.size(), res = ;
if (l < ) return res;
for (int n : nums) {
max_elem = max(max_elem, n);
min_elem = min(min_elem, n);
}
if (max_elem == min_elem) return res;
int bucket_size = (max_elem - min_elem) / l + ;
vector<vector<int>> gaps(l + , vector<int>());
for (int n : nums) {
int bucket_index = (n - min_elem) / bucket_size;
if (gaps[bucket_index].size() == ) {
gaps[bucket_index].push_back(n);
gaps[bucket_index].push_back(n);
} else {
gaps[bucket_index][] = min(n, gaps[bucket_index][]);
gaps[bucket_index][] = max(n, gaps[bucket_index][]);
}
}
int pre = ;
for (int i = ; i < l + ; i++) {
if (gaps[i].size() == ) continue;
res = max(res, gaps[i][] - gaps[pre][]);
pre = i;
}
return res;
}
};
bucket sort
23. Merge k Sorted Lists
https://leetcode.com/problems/merge-k-sorted-lists/description/
Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity.
优先级队列,O(NKlogK)。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Comparison{
public:
bool operator() (ListNode* a, ListNode* b) {
return a->val > b->val;
}
};
class Solution {
public:
ListNode* mergeKLists(vector<ListNode*>& lists) {
priority_queue<ListNode*, vector<ListNode*>, Comparison> q;
for (auto n : lists) {
if (n) q.push(n);
}
ListNode* head = new ListNode(), *tmp = head;
while (!q.empty()) {
auto cur = q.top();
q.pop();
tmp->next = cur;
tmp = cur;
if (cur->next) q.push(cur->next);
}
tmp->next = NULL;
return head->next;
}
};
88. Merge Sorted Array
https://leetcode.com/problems/merge-sorted-array/description/
Given two sorted integer arrays nums1 and nums2, merge nums2 into nums1 as one sorted array. Note:
You may assume that nums1 has enough space (size that is greater or equal to m + n) to hold additional elements from nums2. The number of elements initialized in nums1 and nums2 are m and n respectively.
合并两个排好序的数组。我用了堆,用了temp,空间复杂度过高。最优解是将较长的数组扩充,然后倒着插入,思路类似快排,挖坑填坑。
class Solution {
public:
void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {
int i = m - , j = n - , cur = m + n - ;
while (j >= ) nums1[cur--] = (i >= && nums1[i] > nums2[j]) ? nums1[i--] : nums2[j--];
}
};
239. Sliding Window Maximum
https://leetcode.com/problems/sliding-window-maximum/description/
Given an array nums, there is a sliding window of size k which is moving from the very left of the array to the very right. You can only see the k numbers in the window. Each time the sliding window moves right by one position. For example,
Given nums = [,,-,-,,,,], and k = . Window position Max
--------------- -----
[ -] -
[ - -]
[- - ]
- [- ]
- - [ ]
- - [ ]
Therefore, return the max sliding window as [,,,,,]. Note:
You may assume k is always valid, ie: ≤ k ≤ input array's size for non-empty array. Follow up:
Could you solve it in linear time?
一刷使用java优先级队列(因为c++中的优先级队列没有remove接口)没有判空CE,时间复杂度为O(NK),和暴力求解相比没有优化,因为使用了remove操作。这个题目最好的算法是递归。
class Solution {
public int[] maxSlidingWindow(int[] nums, int k) {
if (nums == null || nums.length == 0) return nums;
PriorityQueue<Integer> q = new PriorityQueue<Integer> (k, new Comparator<Integer>() {
public int compare(Integer o1, Integer o2) {
return o2 - o1;
}
});
int[] res = new int[nums.length - k + 1];
for (int i = 0; i < nums.length; i++) {
if (i >= k) {
q.remove(nums[i - k]);
}
q.offer(nums[i]);
if (i >= k - 1) {
res[i + 1 - k] = q.peek();
}
}
return res;
}
}
295. Find Median from Data Stream
https://leetcode.com/problems/find-median-from-data-stream/description/
Median is the middle value in an ordered integer list. If the size of the list is even, there is no middle value. So the median is the mean of the two middle value. Examples:
[,,] , the median is [,], the median is ( + ) / = 2.5 Design a data structure that supports the following two operations: void addNum(int num) - Add a integer number from the data stream to the data structure.
double findMedian() - Return the median of all elements so far.
For example: addNum()
addNum()
findMedian() -> 1.5
addNum()
findMedian() ->
分别使用小根堆和大根堆存储较大的部分和较小的部分,控制大根堆的size = 小根堆的size或者小根堆的size + 1。一刷没处理好插入元素的大小和大根堆小根堆的size的限制关系,WA。
class MedianFinder {
private:
priority_queue<int, vector<int>, greater<int>> min_heap;
priority_queue<int, vector<int>, less<int>> max_heap;
public:
/** initialize your data structure here. */
MedianFinder() { } void addNum(int num) {
if (max_heap.empty()) {
max_heap.push(num);
} else {
if (num <= max_heap.top()) {
if (max_heap.size() == min_heap.size()) {
max_heap.push(num);
} else {
min_heap.push(max_heap.top());
max_heap.pop();
max_heap.push(num);
}
} else {
if (max_heap.size() == min_heap.size()) {
min_heap.push(num);
max_heap.push(min_heap.top());
min_heap.pop();
} else {
min_heap.push(num);
}
}
}
} double findMedian() {
if (max_heap.size() != min_heap.size()) return (int)max_heap.top();
else return (max_heap.top() + min_heap.top()) / 2.0;
}
}; /**
* Your MedianFinder object will be instantiated and called as such:
* MedianFinder obj = new MedianFinder();
* obj.addNum(num);
* double param_2 = obj.findMedian();
*/
332. Reconstruct Itinerary
https://leetcode.com/problems/reconstruct-itinerary/description/
Given a list of airline tickets represented by pairs of departure and arrival airports [from, to], reconstruct the itinerary in order. All of the tickets belong to a man who departs from JFK. Thus, the itinerary must begin with JFK. Note:
If there are multiple valid itineraries, you should return the itinerary that has the smallest lexical order when read as a single string. For example, the itinerary ["JFK", "LGA"] has a smaller lexical order than ["JFK", "LGB"].
All airports are represented by three capital letters (IATA code).
You may assume all tickets form at least one valid itinerary.
Example :
tickets = [["MUC", "LHR"], ["JFK", "MUC"], ["SFO", "SJC"], ["LHR", "SFO"]]
Return ["JFK", "MUC", "LHR", "SFO", "SJC"].
Example :
tickets = [["JFK","SFO"],["JFK","ATL"],["SFO","ATL"],["ATL","JFK"],["ATL","SFO"]]
Return ["JFK","ATL","JFK","SFO","ATL","SFO"].
Another possible reconstruction is ["JFK","SFO","ATL","JFK","ATL","SFO"]. But it is larger in lexical order.
dfs和heap结合,时间复杂度?思想是path先添加无路可走的节点,使用链表的头插法。c++的list数据结构基于链表实现,接口很多,非常方便,相当于java中的LinkedList。分别使用c++和java刷过,但是都没有一次AC。三刷忘记了基于heap的方法,使用纯DFS加排序。
class Solution {
private:
void dfs(string& start, map<string, priority_queue<string, vector<string>, greater<string>>>& m, list<string>& res) {
while (!m[start].empty()) {
string arrival = m[start].top();
m[start].pop();
dfs(arrival, m, res);
}
res.push_front(start);
}
public:
vector<string> findItinerary(vector<pair<string, string>> tickets) {
map<string, priority_queue<string, vector<string>, greater<string>>> m;
for (auto p : tickets) {
m[p.first].push(p.second);
}
list<string> res;
string start = "JFK";
dfs(start, m, res);
return vector<string>(res.begin(), res.end());
}
};
cpp
class Solution {
private LinkedList<String> path = new LinkedList<>();
private HashMap<String, PriorityQueue<String>> m = new HashMap<>();
public List<String> findItinerary(String[][] tickets) {
for (String[] pair : tickets) {
m.putIfAbsent(pair[], new PriorityQueue<>());
m.get(pair[]).add(pair[]);
}
dfs("JFK");
return path;
}
private void dfs(String departure) {
PriorityQueue<String> q = m.get(departure);
while (q != null && !q.isEmpty()) {
dfs(q.poll());
}
path.addFirst(departure);
}
}
java
class Solution(object):
def findItinerary(self, tickets):
"""
:type tickets: List[List[str]]
:rtype: List[str]
"""
d = {}
visited = [False for _ in range(len(tickets))]
for i in range(len(tickets)):
t = tickets[i]
if t[0] not in d:
d[t[0]] = []
d[t[0]].append(i)
for k in d.keys():
d[k] = sorted(d[k], key=lambda x: tickets[x][1])
path = ["JFK"]
self.dfs(tickets, d, visited, path)
return path def dfs(self, tickets, d, visited, path):
if len(path) == len(tickets) + 1 or path[-1] not in d: return
for t_index in d[path[-1]]:
if not visited[t_index]:
visited[t_index] = True
path.append(tickets[t_index][1])
self.dfs(tickets, d, visited, path)
if len(path) == len(tickets) + 1: return
del path[-1]
visited[t_index] = False
dfs_no_queue
146. LRU Cache
https://leetcode.com/problems/lru-cache/description/
Design and implement a data structure for Least Recently Used (LRU) cache. It should support the following operations: get and put. get(key) - Get the value (will always be positive) of the key if the key exists in the cache, otherwise return -.
put(key, value) - Set or insert the value if the key is not already present. When the cache reached its capacity, it should invalidate the least recently used item before inserting a new item. Follow up:
Could you do both operations in O() time complexity? Example: LRUCache cache = new LRUCache( /* capacity */ ); cache.put(, );
cache.put(, );
cache.get(); // returns 1
cache.put(, ); // evicts key 2
cache.get(); // returns -1 (not found)
cache.put(, ); // evicts key 1
cache.get(); // returns -1 (not found)
cache.get(); // returns 3
cache.get(); // returns 4
hashmap和list。主要利用了stl的list基于双向循环链表实现的性质及其提供的splice接口,使得插入、删除都控制在O(1),而基于hashmap的查找、插入和删除同样是O(1)。注意put操作的实现中,不仅要修改list和相应的迭代器,还有list中的值和map。元素优先级越高在list中的位置越靠前,删除只会在list的尾部进行,而hashmap的删除操作随时随时都可以进行。
list<pair<int, int>> items; unordered_map<int, list<pair<int, int>>::iterator> cache。cache存储key到list中key-value对的迭代器,可以脑补图形。
class LRUCache {
private:
list<pair<int, int>> items;
unordered_map<int, list<pair<int, int>>::iterator> cache;
int _capacity;
public:
LRUCache(int capacity) {
_capacity = capacity;
} int get(int key) {
if (cache.find(key) == cache.end()) {
return -;
} else {
items.splice(items.begin(), items, cache[key]); cache[key] = items.begin();
return cache[key]->second;
}
} void put(int key, int value) {
if (cache.find(key) == cache.end()) {
if (items.size() == _capacity) {
cache.erase(items.back().first); items.pop_back();
}
items.push_front({key, value});
cache[key] = items.begin();
} else {
items.splice(items.begin(), items, cache[key]); cache[key] = items.begin(); cache[key]->second = value;
}
}
}; /**
* Your LRUCache object will be instantiated and called as such:
* LRUCache obj = new LRUCache(capacity);
* int param_1 = obj.get(key);
* obj.put(key,value);
*/
290. Word Pattern
https://leetcode.com/problems/word-pattern/description/
Given a pattern and a string str, find if str follows the same pattern. Here follow means a full match, such that there is a bijection between a letter in pattern and a non-empty word in str. Examples:
pattern = "abba", str = "dog cat cat dog" should return true.
pattern = "abba", str = "dog cat cat fish" should return false.
pattern = "aaaa", str = "dog cat cat dog" should return false.
pattern = "abba", str = "dog dog dog dog" should return false.
Notes:
You may assume pattern contains only lowercase letters, and str contains lowercase letters separated by a single space.
双map,一次AC。
class Solution {
public:
bool wordPattern(string pattern, string str) {
map<char, string> m1;
map<string, char> m2;
stringstream ss(str);
string tmp;
vector<string> strs;
while (getline(ss, tmp, ' ')) {
strs.push_back(tmp);
}
int m = strs.size(), n = pattern.size();
if (m != n) return false;
for (int i = ; i < n; i++) {
if (m1.find(pattern[i]) == m1.end()) {
if (m2.find(strs[i]) != m2.end()) return false;
else {
m1[pattern[i]] = strs[i];
m2[strs[i]] = pattern[i];
}
} else {
if (m2.find(strs[i]) == m2.end()) return false;
else if (m2[strs[i]] != pattern[i] || m1[pattern[i]] != strs[i]) return false;
}
}
return true;
}
};
291. Word Pattern II
https://www.programcreek.com/2014/07/leetcode-word-pattern-ii-java/
This is the extension problem of Word Pattern I. Given a pattern and a string str, find if str follows the same pattern. Here follow means a full match, such that there is a bijection between a letter in pattern and a non-empty substring in str. Examples:
pattern = "abab", str = "redblueredblue" should return true.
pattern = "aaaa", str = "asdasdasdasd" should return true.
pattern = "aabb", str = "xyzabcxzyabc" should return false.
双map和dfs结合,一刷没AC,strStart应该更新为i + 1而不是i。
import java.util.HashMap; public class WordPatternII {
public static void main(String[] args) {
String pattern = "aabb";
String str = "redredbluebune";
if (wordPattern(pattern, str)) System.out.println("yes");
else System.out.println("No");
} private static boolean wordPattern(String pattern, String str) {
HashMap<Character, String> m1 = new HashMap<>();
HashMap<String, Character> m2 = new HashMap<>();
return dfs(pattern, str, 0, 0, m1, m2);
} private static boolean dfs(String pattern, String str, int patternStart, int strStart,
HashMap<Character, String> m1, HashMap<String, Character> m2) {
if (patternStart == pattern.length()) {
return strStart == str.length();
}
for (int i = strStart; i < str.length(); i++) {
String tmp = str.substring(strStart, i + 1);
if (m1.containsKey(pattern.charAt(patternStart))) {
if (m2.containsKey(tmp) && m2.get(tmp) == pattern.charAt(patternStart) &&
m1.get(pattern.charAt(patternStart)).equals(tmp)) {
if (dfs(pattern, str, patternStart + 1, i + 1, m1, m2)) return true;
}
} else {
if (!m2.containsKey(tmp)) {
m1.put(pattern.charAt(patternStart), tmp);
m2.put(tmp, pattern.charAt(patternStart));
if (dfs(pattern, str, patternStart + 1, i + 1, m1, m2)) return true;
m1.remove(pattern.charAt(patternStart));
m2.remove(tmp);
}
}
}
return false;
}
}
双map+dfs
734. Sentence Similarity
https://leetcode.com/contest/weekly-contest-60/problems/sentence-similarity/
Given two sentences words1, words2 (each represented as an array of strings), and a list of similar word pairs pairs, determine if two sentences are similar. For example, "great acting skills" and "fine drama talent" are similar, if the similar word pairs are pairs = [["great", "fine"], ["acting","drama"], ["skills","talent"]]. Note that the similarity relation is not transitive. For example, if "great" and "fine" are similar, and "fine" and "good" are similar, "great" and "good" are not necessarily similar. However, similarity is symmetric. For example, "great" and "fine" being similar is the same as "fine" and "great" being similar. Also, a word is always similar with itself. For example, the sentences words1 = ["great"], words2 = ["great"], pairs = [] are similar, even though there are no specified similar word pairs. Finally, sentences can only be similar if they have the same number of words. So a sentence like words1 = ["great"] can never be similar to words2 = ["doubleplus","good"]. Note: The length of words1 and words2 will not exceed .
The length of pairs will not exceed .
The length of each pairs[i] will be .
The length of each words[i] and pairs[i][j] will be in the range [, ].
map,没理解题意,sentence相似要求每个位置的word都相似!第一次用python刷题,比c++快多了,在数据结构涉及set,string等结构时,python非常方便。
class Solution(object):
def areSentencesSimilar(self, words1, words2, pairs):
"""
:type words1: List[str]
:type words2: List[str]
:type pairs: List[List[str]]
:rtype: bool
"""
if len(words1) != len(words2): return False
d = {}
for p in pairs:
if p[] not in d:
d[p[]] = set()
if p[] not in d:
d[p[]] = set()
d[p[]].add(p[])
d[p[]].add(p[])
for w in words1:
if w not in d:
d[w] = set()
d[w].add(w)
for w in words2:
if w not in d:
d[w] = set()
d[w].add(w)
for i in range(len(words1)):
if words2[i] not in d[words1[i]]:
return False
return True
525. Contiguous Array
https://leetcode.com/problems/contiguous-array/description/
Given a binary array, find the maximum length of a contiguous subarray with equal number of and . Example :
Input: [,]
Output:
Explanation: [, ] is the longest contiguous subarray with equal number of and .
Example :
Input: [,,]
Output:
Explanation: [, ] (or [, ]) is a longest contiguous subarray with equal number of and .
Note: The length of the given binary array will not exceed ,.
核心公式diff[i, j] = diff[0,j] - diff[0,i],diff表示1比0多的个数,数组的一小段的diff等于整个数组的起始位置到段结尾的diff减去全数组起始位置到段起始的diff。当两个diff相等,表示中间的小段0和1的个数相同,更新结果。一刷没AC,注意处理空数组(diff要多加一个空位,map也要!)。
class Solution {
public:
int findMaxLength(vector<int>& nums) {
int n = nums.size();
map<int, int> m;
int res = ;
vector<int> v(n + , );
m[] = ;
for (int i = ; i < n; i++) {
v[i + ] = v[i] + (nums[i] == ? - : );
auto iter = m.find(v[i + ]);
if (iter != m.end()) {
res = max(res, i + - iter->second);
} else m[v[i + ]] = i + ;
}
return res;
}
};
76. Minimum Window Substring
https://leetcode.com/problems/minimum-window-substring/description/
Given a string S and a string T, find the minimum window in S which will contain all the characters in T in complexity O(n). For example,
S = "ADOBECODEBANC"
T = "ABC"
Minimum window is "BANC". Note:
If there is no such window in S that covers all characters in T, return the empty string "". If there are multiple such windows, you are guaranteed that there will always be only one unique minimum window in S.
TP,将直通硅谷老师的思路改进如下:
1. 分别用aMap与tMap(vector实现)存储符合条件的子串([i, ……,j])与T中的字符及频率。
2. for循环遍历j(每轮循环先更新j,然后固定j更新i):
2a. 先将s[j]添加到aMap中
2b. 尝试更新count和include
2c. 如果[i, ……, j]满足条件,使用while循环尝试右移i,移动过程中优先更新min_len和min_start,如果不能再右移直接退出while循环。
class Solution {
public:
string minWindow(string s, string t) {
int count = t.size(), min_start = , min_len = INT_MAX;
bool include = false;
vector<int> tMap(), aMap();
for (char c : t) tMap[c]++;
for (int i = , j = ; j < s.size(); j++) {
aMap[s[j]]++;
if (count > && tMap[s[j]] >= aMap[s[j]]) count--;
if (count == ) include = true;
if (include) {
while (i <= j) {
if (min_len > j - i + ) {
min_len = j - i + ; min_start = i;
}
if (tMap[s[i]] > && aMap[s[i]] == tMap[s[i]]) break;
else {
aMap[s[i]]--; i++;
}
}
}
}
return include ? s.substr(min_start, min_len) : "";
}
};
207. Course Schedule
https://leetcode.com/problems/course-schedule/description/
There are a total of n courses you have to take, labeled from to n - . Some courses may have prerequisites, for example to take course you have to first take course , which is expressed as a pair: [,] Given the total number of courses and a list of prerequisite pairs, is it possible for you to finish all courses? For example: , [[,]]
There are a total of courses to take. To take course you should have finished course . So it is possible. , [[,],[,]]
There are a total of courses to take. To take course you should have finished course , and to take course you should also have finished course . So it is impossible. Note:
The input prerequisites is a graph represented by a list of edges, not adjacency matrices. Read more about how a graph is represented.
You may assume that there are no duplicate edges in the input prerequisites.
graph拓扑排序,算法复杂度有点高,可继续优化!一次AC。
class Solution {
public:
bool canFinish(int numCourses, vector<pair<int, int>>& prerequisites) {
map<int, set<int>> m;
for (int i = ; i < numCourses; i++) {
m[i] = set<int>();
}
for (auto p : prerequisites) {
m[p.first].insert(p.second);
}
queue<int> q;
for (auto iter = m.begin(); iter != m.end(); iter++) {
if (iter->second.size() == ) {
q.push(iter->first);
numCourses--;
}
}
while (!q.empty() && numCourses > ) {
int cur = q.front();
q.pop();
for (auto iter = m.begin(); iter != m.end(); iter++) {
if (iter->second.find(cur) != iter->second.end()) {
iter->second.erase(cur);
if (iter->second.size() == ) {
q.push(iter->first);
numCourses--;
}
}
}
}
return numCourses == ;
}
};
210. Course Schedule II
https://leetcode.com/problems/course-schedule-ii/description/
There are a total of n courses you have to take, labeled from to n - . Some courses may have prerequisites, for example to take course you have to first take course , which is expressed as a pair: [,] Given the total number of courses and a list of prerequisite pairs, return the ordering of courses you should take to finish all courses. There may be multiple correct orders, you just need to return one of them. If it is impossible to finish all courses, return an empty array. For example: , [[,]]
There are a total of courses to take. To take course you should have finished course . So the correct course order is [,] , [[,],[,],[,],[,]]
There are a total of courses to take. To take course you should have finished both courses and . Both courses and should be taken after you finished course . So one correct course order is [,,,]. Another correct ordering is[,,,]. Note:
The input prerequisites is a graph represented by a list of edges, not adjacency matrices. Read more about how a graph is represented.
You may assume that there are no duplicate edges in the input prerequisites.
graph拓扑排序,和上一道比仅仅是输出结果有变化。
class Solution {
public:
vector<int> findOrder(int numCourses, vector<pair<int, int>>& prerequisites) {
vector<set<int>> graph(numCourses, set<int>());
for (auto p : prerequisites) graph[p.first].insert(p.second);
queue<int> q;
for (int i = ; i < numCourses; i++) {
if (graph[i].size() == ) q.push(i);
}
vector<int> res;
queue<int> next;
while (!q.empty()) {
int cur = q.front();
q.pop();
res.push_back(cur);
for (int i = ; i < numCourses; i++) {
if (graph[i].find(cur) != graph[i].end()) {
graph[i].erase(cur);
if (graph[i].size() == ) next.push(i);
}
}
if (q.empty()) swap(q, next);
}
return res.size() == numCourses ? res : vector<int> ();
}
};
269. Alien Dictionary
http://blog.csdn.net/qq508618087/article/details/50981000
Alien Dictionary
There is a new alien language which uses the latin alphabet. However, the order among letters are unknown to you. You receive a list of words from the dictionary, where words are sorted lexicographically by the rules of this new language. Derive the order of letters in this language.
For example,
Given the following words in dictionary,
[ "wrt", "wrf", "er", "ett", "rftt"] The correct order is: "wertf".
这是一道有锁题,graph的拓扑排序。一次AC。
import java.util.*; public class AlienDictionary {
public static void main (String[] args) {
String[] words = {"wrt", "wrf", "er", "ett", "rftt"};
System.out.printf("%s%n", alienOrder(words));
} private static String alienOrder(String[] words) {
StringBuilder res = new StringBuilder("");
Set<Character> chars = new HashSet<>();
HashMap<Character, Set<Character> > graph = new HashMap<>();
for (String word : words) {
for (int i = 0; i < word.length(); i++) chars.add(word.charAt(i));
}
for (Character c : chars) {
graph.putIfAbsent(c, new HashSet<>());
}
for (int i = 0; i < words.length; i++) {
for (int j = i + 1; j < words.length; j++) {
int k = 0, maxIndex = Math.min(words[i].length(), words[j].length());
while (k < maxIndex && words[i].charAt(k) == words[j].charAt(k)) k++;
if (k < maxIndex) graph.get(words[j].charAt(k)).add(words[i].charAt(k));
}
}
Queue<Character> q = new LinkedList<>();
for (char c: chars) {
if (graph.get(c).size() == 0) {
q.add(c);
res.append(c);
}
}
while (!q.isEmpty()) {
char cur = q.poll();
for (char c : chars) {
if (graph.get(c).contains(cur)) {
graph.get(c).remove(cur);
if (graph.get(c).size() == 0) {
res.append(c);
q.offer(c);
}
}
}
}
String finalRes = res.toString();
return finalRes.length() == chars.size() ? finalRes : "";
}
}
310. Minimum Height Trees
https://leetcode.com/problems/minimum-height-trees/description/
For a undirected graph with tree characteristics, we can choose any node as the root. The result graph is then a rooted tree. Among all possible rooted trees, those with minimum height are called minimum height trees (MHTs). Given such a graph, write a function to find all the MHTs and return a list of their root labels. Format
The graph contains n nodes which are labeled from to n - . You will be given the number n and a list of undirected edges (each edge is a pair of labels). You can assume that no duplicate edges will appear in edges. Since all edges are undirected, [, ] is the same as [, ] and thus will not appear together in edges. Example : Given n = , edges = [[, ], [, ], [, ]] | / \ return [] Example : Given n = , edges = [[, ], [, ], [, ], [, ], [, ]] \ | / | | return [, ] Note: () According to the definition of tree on Wikipedia: “a tree is an undirected graph in which any two vertices are connected by exactly one path. In other words, any connected graph without simple cycles is a tree.” () The height of a rooted tree is the number of edges on the longest downward path between the root and a leaf.
graph的拓扑排序。这类题中较难的一类,有点弯。
class Solution {
public:
vector<int> findMinHeightTrees(int n, vector<pair<int, int>>& edges) {
vector< set<int> > graph(n, set<int>());
for (pair<int, int> p : edges) {
graph[p.first].insert(p.second);
graph[p.second].insert(p.first);
}
queue<int> leaves;
for (int i = ; i < n; i++) {
if (graph[i].size() <= ) leaves.push(i);
}
while (n > ) {
n -= leaves.size();
queue<int> new_leaves;
while (!leaves.empty()) {
int cur = leaves.front();
leaves.pop();
int neighbor = *(graph[cur].begin());
graph[cur].erase(neighbor);
graph[neighbor].erase(cur);
if (graph[neighbor].size() == ) new_leaves.push(neighbor);
}
leaves = new_leaves;
}
vector<int> res;
while (!leaves.empty()) {
res.push_back(leaves.front());
leaves.pop();
}
return res;
}
};
399. Evaluate Division
https://leetcode.com/problems/evaluate-division/description/
Equations are given in the format A / B = k, where A and B are variables represented as strings, and k is a real number (floating point number). Given some queries, return the answers. If the answer does not exist, return -1.0. Example:
Given a / b = 2.0, b / c = 3.0.
queries are: a / c = ?, b / a = ?, a / e = ?, a / a = ?, x / x = ? .
return [6.0, 0.5, -1.0, 1.0, -1.0 ]. The input is: vector<pair<string, string>> equations, vector<double>& values, vector<pair<string, string>> queries , where equations.size() == values.size(), and the values are positive. This represents the equations. Return vector<double>. According to the example above: equations = [ ["a", "b"], ["b", "c"] ],
values = [2.0, 3.0],
queries = [ ["a", "c"], ["b", "a"], ["a", "e"], ["a", "a"], ["x", "x"] ].
The input is always valid. You may assume that evaluating the queries will result in no division by zero and there is no contradiction.
graph的dfs, 一次AC,但是有些typo!感觉自己刷题变厉害了一点,套路题已经不怕了。
class Solution {
private:
void query(map<string, map<string, float>>& m, pair<string, string> p, int i, vector<double>& res, set<string>& visited) {
if (m.find(p.first) != m.end()) {
if (m[p.first].find(p.second) != m[p.first].end()) {
res[i] = m[p.first][p.second];
return;
} else {
visited.insert(p.first);
for (auto iter = m[p.first].begin(); iter != m[p.first].end(); iter++) {
if (visited.find(iter->first) == visited.end()) {
query(m, make_pair(iter->first, p.second), i, res, visited);
if (res[i] != -) {
res[i] *= m[p.first][iter->first];
m[p.first][p.second] = res[i];
m[p.second][p.first] = / res[i];
return;
}
}
}
}
} else {
return;
}
}
public:
vector<double> calcEquation(vector<pair<string, string>> equations, vector<double>& values, vector<pair<string, string>> queries) {
map<string, map<string, float> > m;
for (int i = ; i < equations.size(); i++) {
auto p = equations[i];
m[p.first][p.second] = values[i];
m[p.first][p.first] = 1.0;
m[p.second][p.second] = 1.0;
m[p.second][p.first] = / values[i];
}
vector<double> res(queries.size(), -);
for (int i = ; i < queries.size(); i++) {
set<string> visited;
query(m, queries[i], i, res, visited);
}
return res;
}
};
393. UTF-8 Validation
https://leetcode.com/problems/utf-8-validation/description/
A character in UTF8 can be from to bytes long, subjected to the following rules: For -byte character, the first bit is a , followed by its unicode code.
For n-bytes character, the first n-bits are all one's, the n+1 bit is 0, followed by n-1 bytes with most significant 2 bits being 10.
This is how the UTF- encoding would work: Char. number range | UTF- octet sequence
(hexadecimal) | (binary)
--------------------+---------------------------------------------
- 007F | 0xxxxxxx
- 07FF | 110xxxxx 10xxxxxx
- FFFF | 1110xxxx 10xxxxxx 10xxxxxx
- FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
Given an array of integers representing the data, return whether it is a valid utf- encoding. Note:
The input is an array of integers. Only the least significant bits of each integer is used to store the data. This means each integer represents only byte of data. Example : data = [, , ], which represents the octet sequence: . Return true.
It is a valid utf- encoding for a -bytes character followed by a -byte character.
Example : data = [, , ], which represented the octet sequence: . Return false.
The first bits are all one's and the 4th bit is 0 means it is a 3-bytes character.
The next byte is a continuation byte which starts with and that's correct.
But the second continuation byte does not start with , so it is invalid.
dfs和位运算,注意位运算的优先级没有判断符号优先级高!位运算的优先级很低!
class Solution {
private:
bool dfs(vector<int>& data, int start) {
if (start >= data.size()) return true;
for (int i = ; i < && i + start < data.size(); i++) {
switch (i){
case :{
if ((data[start] & 0x80) == && dfs(data, start + )) return true;
break;
}
case : {
if ((data[start] & 0xe0) == 0xc0 && (data[start + ] & 0xc0) == 0x80 && dfs(data, start + )) return true;
break;
} case : {
if ((data[start] & 0xf0) == 0xe0 && (data[start + ] & 0xc0) == 0x80 && (data[start + ] & 0xc0) == 0x80 && dfs(data, start + )) return true;
break;
} case :{
if ((data[start] & 0xf8) == 0xf0 && (data[start + ] & 0xc0) == 0x80 && (data[start + ] & 0xc0) == 0x80 && (data[start + ] & 0xc0) == 0x80 && dfs(data, start + )) return true;
break;
}
default:
break;
}
}
return false;
}
public:
bool validUtf8(vector<int>& data) {
return dfs(data, );
}
};
dfs
617. Merge Two Binary Trees
https://leetcode.com/problems/merge-two-binary-trees/description/
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
TreeNode* mergeTrees(TreeNode* t1, TreeNode* t2) {
TreeNode* root;
if (t1 && t2) {
t1->val += t2->val;
root = t1;
root->left = mergeTrees(t1->left, t2->left);
root->right = mergeTrees(t1->right, t2->right);
}
else if (t1) root = t1;
else if (t2) root = t2;
else root = NULL;
return root;
}
};
简单递归
637. Average of Levels in Binary Tree
https://leetcode.com/problems/average-of-levels-in-binary-tree/description/
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
vector<double> averageOfLevels(TreeNode* root) {
queue<TreeNode*> q, next;
vector<double> res;
q.push(root);
double sum = , l = q.size();
while (!q.empty()) {
auto cur = q.front();
sum += cur->val;
if (cur->left) next.push(cur->left);
if (cur->right) next.push(cur->right);
q.pop();
if (q.empty()) {
res.push_back(sum / l);
sum = ;
l = next.size();
swap(q, next);
}
}
return res;
}
};
双queue层序遍历
653. Two Sum IV - Input is a BST
https://leetcode.com/problems/two-sum-iv-input-is-a-bst/description/
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
private:
TreeNode* find_v(TreeNode* root, int k) {
if (!root) return root;
if (k > root->val) return find_v(root->right, k);
else if (k < root->val) return find_v(root->left, k);
else return root;
}
bool re(TreeNode* cur, TreeNode* t, int k) {
if (!cur) return false;
auto p = find_v(t, k - cur->val);
if (p && p!= cur) return true;
else return re(cur->left, t, k) || re(cur->right, t, k);
}
public:
bool findTarget(TreeNode* root, int k) {
return re(root, root, k);
}
};
递归,BST查找,想复杂了!
538. Convert BST to Greater Tree
https://leetcode.com/problems/convert-bst-to-greater-tree/description/
一开始思路不好,只想着记录父节点,导致重复计算,要再想一下为什么!使用sum记录当前访问的最大值,是最吼的,逆先序遍历即可。
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
private:
int s = 0;
void dfs(TreeNode* root) {
if (!root) return;
if (root->right) {
dfs(root->right);
}
root->val = (s += root->val);
if (root->left) {
dfs(root->left);
}
}
public:
TreeNode* convertBST(TreeNode* root) {
dfs(root);
return root;
}
};
563. Binary Tree Tilt
https://leetcode.com/problems/binary-tree-tilt/description/
自己的思路RE,想破头没想明白,大佬的思路比我的简洁,只用了一个递归!我的用了两个递归!
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
int res = ;
int find_sum(TreeNode* root) {
if (!root) return ;
int left = find_sum(root->left);
int right = find_sum(root->right);
res += abs(left - right);
return left + right + root->val;
}
int findTilt(TreeNode* root) {
find_sum(root);
return res;
}
};
572. Subtree of Another Tree
https://leetcode.com/problems/subtree-of-another-tree/description/
两个递归,效率略低。
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
private:
bool isSame(TreeNode* t, TreeNode* s) {
if (!t && !s) return true;
else if(s && t && s->val == t->val) return isSame(t->left, s->left) && isSame(t->right, s->right);
return false;
}
public:
bool isSubtree(TreeNode* s, TreeNode* t) {
if (isSame(s, t)) return true;
if (s) return isSubtree(s->left, t) || isSubtree(s->right, t);
return false;
}
};
437. Path Sum III
https://leetcode.com/problems/path-sum-iii/description/
双递归,注意空节点的处理。不能靠子节点判断父节点的值的情况,因为子节点有两个,这样容易导致重复。
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
void dfs(TreeNode* t, int s, int& res) {
if (s == t->val) res += ;
if (t->left) dfs(t->left, s - t->val, res);
if (t->right) dfs(t->right, s - t->val, res);
}
int pathSum(TreeNode* root, int sum) {
int res = ;
if (!root) return res;
dfs(root, sum, res);
if (root->left) res += pathSum(root->left, sum);
if (root->right) res += pathSum(root->right, sum);
return res;
}
};
501. Find Mode in Binary Search Tree
https://leetcode.com/problems/find-mode-in-binary-search-tree/description/
Given a binary search tree (BST) with duplicates, find all the mode(s) (the most frequently occurred element) in the given BST. Assume a BST is defined as follows: The left subtree of a node contains only nodes with keys less than or equal to the node's key.
The right subtree of a node contains only nodes with keys greater than or equal to the node's key.
Both the left and right subtrees must also be binary search trees.
For example:
Given BST [,null,,], \ / return []. Note: If a tree has more than one mode, you can return them in any order. Follow up: Could you do that without using any extra space? (Assume that the implicit stack space incurred due to recursion does not count).
双递归,子递归一刷没考虑清楚,Mode中的数字不一定都连着,要利用BST的性质!
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
private:
int max = ;
vector<int> res;
int findSame(TreeNode* root, int t) {
int res = ;
if (!root) return ;
if (root->val == t) res++;
if (root->val >= t) res += findSame(root->left, t);
if (root->val <= t) res += findSame(root->right, t);
return res;
}
public:
vector<int> findMode(TreeNode* root) {
if (!root) return res;
int c = findSame(root, root->val);
if (c > max) {
res.clear();
max = c;
res.push_back(root->val);
} else if (c == max) res.push_back(root->val);
findMode(root->left);
findMode(root->right);
return res;
}
};
687. Longest Univalue Path
https://leetcode.com/problems/longest-univalue-path/description/
Given a binary tree, find the length of the longest path where each node in the path has the same value. This path may or may not pass through the root. Note: The length of path between two nodes is represented by the number of edges between them. Example : Input: / \ / \ \ Output: Example : Input: / \ / \ \ Output: Note: The given binary tree has not more than nodes. The height of the tree is not more than .
双递归。
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
private:
int maxLength = ;
int pathLen(TreeNode* root, int t) {
int res = ;
if (!root) return res;
if (root->val == t) {
res++;
res += max(pathLen(root->left, t), pathLen(root->right, t));
return res;
} else return res;
}
public:
int longestUnivaluePath(TreeNode* root) {
if (!root) return ;
int left = , right = ;
if (root->left) left = pathLen(root->left, root->val);
if (root->right) right = pathLen(root->right, root->val);
maxLength = max(left + right, maxLength);
longestUnivaluePath(root->left);
longestUnivaluePath(root->right);
return maxLength;
}
};
654. Maximum Binary Tree
Given an integer array with no duplicates. A maximum tree building on this array is defined as follow: The root is the maximum number in the array.
The left subtree is the maximum tree constructed from left part subarray divided by the maximum number.
The right subtree is the maximum tree constructed from right part subarray divided by the maximum number.
Construct the maximum tree by the given array and output the root node of this tree. Example :
Input: [,,,,,]
Output: return the tree root node representing the following tree: / \ \ / \ Note:
The size of the given array will be in the range [,].
https://leetcode.com/problems/maximum-binary-tree/description/
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
private:
TreeNode* dfs(vector<int>& nums, int l, int r) {
if (l >= r) return NULL;
int max_index = l;
for (int i = l; i < r; i++) max_index = nums[max_index] < nums[i] ? i : max_index;
TreeNode* root = new TreeNode(nums[max_index]);
root->left = dfs(nums, l, max_index);
root->right = dfs(nums, max_index + , r);
return root;
}
public:
TreeNode* constructMaximumBinaryTree(vector<int>& nums) {
return dfs(nums, , nums.size());
}
};
树的递归。
145. Binary Tree Postorder Traversal
https://leetcode.com/problems/binary-tree-postorder-traversal/description/
二叉树后续遍历递归与非递归实现。多做是有用的,非常有用,做这个题的时候深有体会!
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
struct Node{
TreeNode* n;
bool visited;
Node(TreeNode* t): n(t), visited(false){};
};
class Solution {
private:
void dfs(TreeNode* root, vector<int>& res) {
if (!root) return;
dfs(root->left, res);
dfs(root->right, res);
res.push_back(root->val);
}
public:
vector<int> postorderTraversal(TreeNode* root) {
vector<int> res();
if (!root) return res;
stack<Node*> s;
s.push(new Node(root));
while (s.top()->n->left) s.push(new Node(s.top()->n->left));
while (!s.empty()) {
auto cur = s.top();
if (!cur->n->right || cur->visited) {
s.pop();
res.push_back(cur->n->val);
}
else {
cur->visited = true;
s.push(new Node(cur->n->right));
while (s.top()->n->left) s.push(new Node(s.top()->n->left));
}
}
return res;
}
};
none recursion
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
private:
void dfs(TreeNode* root, vector<int>& res) {
if (!root) return;
dfs(root->left, res);
dfs(root->right, res);
res.push_back(root->val);
}
public:
vector<int> postorderTraversal(TreeNode* root) {
vector<int> res();
dfs(root, res);
return res;
}
};
recursion
655. Print Binary Tree
https://leetcode.com/problems/print-binary-tree/description/
Print a binary tree in an m*n 2D string array following these rules: The row number m should be equal to the height of the given binary tree.
The column number n should always be an odd number.
The root node's value (in string format) should be put in the exactly middle of the first row it can be put. The column and the row where the root node belongs will separate the rest space into two parts (left-bottom part and right-bottom part). You should print the left subtree in the left-bottom part and print the right subtree in the right-bottom part. The left-bottom part and the right-bottom part should have the same size. Even if one subtree is none while the other is not, you don't need to print anything for the none subtree but still need to leave the space as large as that for the other subtree. However, if two subtrees are none, then you don't need to leave space for both of them.
Each unused space should contain an empty string "".
Print the subtrees following the same rules.
Example :
Input: / Output:
[["", "", ""],
["", "", ""]]
Example :
Input: / \ \ Output:
[["", "", "", "", "", "", ""],
["", "", "", "", "", "", ""],
["", "", "", "", "", "", ""]]
Example :
Input: / \ / / Output: [["", "", "", "", "", "", "", "", "", "", "", "", "", "", ""]
["", "", "", "", "", "", "", "", "", "", "", "", "", "", ""]
["", "", "", "", "", "", "", "", "", "", "", "", "", "", ""]
["", "", "", "", "", "", "", "", "", "", "", "", "", "", ""]]
Note: The height of binary tree is in the range of [, ].
合并左右子树的时候思路要清晰,分情况,不是两边一直用空串填充,而是每个元素两侧都使用空串填充!一步步简化代码,对容器的insert函数用熟了!
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
vector<vector<string>> printTree(TreeNode* root) {
vector<vector<string> > res(, vector<string>());
if (!root) return res;
auto left = printTree(root->left);
auto right = printTree(root->right);
int row_l = left.size(), row_r = right.size(), column_l = , column_r = ;
if (row_l) column_l = left[].size();
if (row_r) column_r = right[].size();
int r = max(row_l, row_r), c = max(column_l, column_r);
vector<string> first_row( * c + , "");
first_row[c] = to_string(root->val);
for (int i = ; i < r; i++) {
// 左边为空
if (row_l <= i) left.push_back(vector<string>(, ""));
// 左侧为空
if (row_r <= i) right.push_back(vector<string>(, ""));
// 左侧宽度不够
while (left[i].size() != c) {
vector<string> tmp( * left[i].size() + , "");
for (int j = ; j < left[i].size(); j++) tmp[ * j + ] = left[i][j];
left[i] = tmp;
}
// 右侧宽度不够
while(right[i].size() != c) {
vector<string> tmp( * right[i].size() + , "");
for (int j = ; j < right[i].size(); j++) tmp[ * j + ] = right[i][j];
right[i] = tmp;
}
left[i].push_back("");
left[i].insert(left[i].end(), right[i].begin(), right[i].end());
}
left.insert(left.begin(), first_row);
return left;
}
};
623. Add One Row to Tree
https://leetcode.com/problems/add-one-row-to-tree/description/
Given the root of a binary tree, then value v and depth d, you need to add a row of nodes with value v at the given depth d. The root node is at depth . The adding rule is: given a positive integer depth d, for each NOT null tree nodes N in depth d-, create two tree nodes with value v as N's left subtree root and right subtree root. And N's original left subtree should be the left subtree of the new left subtree root, its original right subtree should be the right subtree of the new right subtree root. If depth d is that means there is no depth d- at all, then create a tree node with value v as the new root of the whole original tree, and the original tree is the new root's left subtree. Example :
Input:
A binary tree as following: / \ / \ / v = d = Output: / \ / \ / \ / Example :
Input:
A binary tree as following: / / \ v = d = Output: / / \ / \ Note:
The given d is in range [, maximum depth of the given tree + ].
The given binary tree has at least one tree node.
树的层序遍历(双queue),注意要保存更上一层的节点,添加子树时不必考虑子树是否为空!
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
TreeNode* addOneRow(TreeNode* root, int v, int d) {
if (d == ) {
TreeNode* t = new TreeNode(v);
t->left = root;
return t;
}
queue<TreeNode*> q;
q.push(root);
int l = ;
while (!q.empty() && l < d - ) {
queue<TreeNode*> next;
while (!q.empty()) {
auto cur = q.front();
q.pop();
if (cur->left) next.push(cur->left);
if (cur->right) next.push(cur->right);
}
swap(q, next);
l++;
}
while (!q.empty()) {
TreeNode* p = q.front();
q.pop();
if (p->left) {
TreeNode* new_left = new TreeNode(v);
new_left->left = p->left;
p->left = new_left;
}
if (p->right) {
TreeNode* new_right = new TreeNode(v);
new_right->right = p->right;
p->right = new_right;
}
}
return root;
}
};
337. House Robber III
https://leetcode.com/problems/house-robber-iii/description/
The thief has found himself a new place for his thievery again. There is only one entrance to this area, called the "root." Besides the root, each house has one and only one parent house. After a tour, the smart thief realized that "all houses in this place forms a binary tree". It will automatically contact the police if two directly-linked houses were broken into on the same night. Determine the maximum amount of money the thief can rob tonight without alerting the police. Example : / \ \ \ Maximum amount of money the thief can rob = + + = .
Example : / \ / \ \ Maximum amount of money the thief can rob = + = .
递归,有点0-1背包的意思。
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
int rob(TreeNode* root) {
if (!root) return ;
int left = rob(root->left), right = rob(root->right), l = , r = ;
if (root->left) l = rob(root->left->left) + rob(root->left->right);
if (root->right) r = rob(root->right->left) + rob(root->right->right);
return max(left + right, root->val + l + r);
}
};
662. Maximum Width of Binary Tree
https://leetcode.com/problems/maximum-width-of-binary-tree/description/
Given a binary tree, write a function to get the maximum width of the given tree. The width of a tree is the maximum width among all levels. The binary tree has the same structure as a full binary tree, but some nodes are null. The width of one level is defined as the length between the end-nodes (the leftmost and right most non-null nodes in the level, where the null nodes between the end-nodes are also counted into the length calculation. Example :
Input: / \ / \ \ Output:
Explanation: The maximum width existing in the third level with the length (,,null,).
Example :
Input: / / \ Output:
Explanation: The maximum width existing in the third level with the length (,).
Example :
Input: / \ / Output:
Explanation: The maximum width existing in the second level with the length (,).
Example :
Input: / \ / \ / \ Output:
Explanation:The maximum width existing in the fourth level with the length (,null,null,null,null,null,null,). Note: Answer will in the range of -bit signed integer.
一刷使用BFS,当树的高度过大时,内存溢出。
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
int widthOfBinaryTree(TreeNode* root) {
int res = ;
if (!root) return res;
queue<TreeNode*> q, next;
q.push(root);
vector<TreeNode*> level;
while (!q.empty()) {
level.clear();
while (!q.empty()) {
auto cur = q.front();
q.pop();
level.push_back(cur);
if (cur) {
next.push(cur->left);
next.push(cur->right);
} else {
next.push(NULL);
next.push(NULL);
}
}
swap(q, next);
int b = -, e = level.size();
for (int i = ; i < level.size(); i++) {
if (level[i]) {
b = i;
break;
}
}
if (b == -) return res;
for (int i = level.size() - ; i >= ; i--) {
if (level[i]) {
e = i;
break;
}
}
res = max(res, e - b + );
}
return res;
}
};
bfs-mle
二刷基于BFS,利用满二叉树的性质(子节点和父节点index之间的关系,左子index = 父节点index * 2, 右子index = 父节点index * 2 + 1)AC。
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
int widthOfBinaryTree(TreeNode* root) {
int res = ;
if (!root) return res;
queue<pair<TreeNode*, int>> q, next;
q.push(make_pair(root, ));
res = ;
while (!q.empty()) {
int l = q.front().second, r = l;
while (!q.empty()) {
auto cur = q.front();
q.pop();
r = cur.second;
if (cur.first->left) next.push(make_pair(cur.first->left, cur.second * ));
if (cur.first->right) next.push(make_pair(cur.first->right, cur.second * + ));
}
swap(q, next);
res = max(res, r - l + );
}
return res;
}
};
bfs-full-binary-tree
129. Sum Root to Leaf Numbers
https://leetcode.com/problems/sum-root-to-leaf-numbers/description/
Given a binary tree containing digits from - only, each root-to-leaf path could represent a number. An example is the root-to-leaf path ->-> which represents the number . Find the total sum of all root-to-leaf numbers. For example, / \ The root-to-leaf path -> represents the number .
The root-to-leaf path -> represents the number . Return the sum = + = .
dfs。遇到叶子节点就把num(表示path)加到res上。如果follow up将节点的数只有1位的限制去掉,可以使用vector表示path。
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
int sumNumbers(TreeNode* root) {
int res = , num = ;
dfs(root, res, num);
return res;
}
void dfs(TreeNode* root, int& res, int& num) {
if (!root) return;
num = num * + root->val;
if (!root->left && !root->right) res += num;
if (root->left) dfs(root->left, res, num);
if (root->right) dfs(root->right, res, num);
num /= ;
}
};
dfs
450. Delete Node in a BST
https://leetcode.com/problems/delete-node-in-a-bst/description/
Given a root node reference of a BST and a key, delete the node with the given key in the BST. Return the root node reference (possibly updated) of the BST. Basically, the deletion can be divided into two stages: Search for a node to remove.
If the node is found, delete the node.
Note: Time complexity should be O(height of tree). Example: root = [,,,,,null,]
key = / \ / \ \ Given key to delete is . So we find the node with value and delete it. One valid answer is [,,,,null,null,], shown in the following BST. / \ / \ Another valid answer is [,,,null,,null,]. / \ \ \
好题!删除BST中的节点,上课讲过,自己做还是废了不少时间。递归删除节点,找到节点后分情况讨论,找左子树的最大值或者右子树的最小值作为新的根的值,并删除原节点,findAndDelete函数要注意删除节点不能直接将父节点的右子树设为NULL,要设为删除节点的左子树!
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
private:
int findAndDelete(TreeNode* node) {
int res;
if (!node->left->right) {
res = node->left->val;
node->left = node->left->left;
return res;
}
TreeNode* p = node->left;
node = node->left->right;
while (node->right) {
p = node;
node = node->right;
}
p->right = node->left;
return node->val;
}
public:
TreeNode* deleteNode(TreeNode* root, int key) {
if (!root) return root;
if (root->val == key) {
if (root->right && root->left) {
int val = findAndDelete(root);
root->val = val;
}
else if (!root->right && !root->left) return NULL;
else {
TreeNode* tmp;
if (root->right) tmp = root->right;
else tmp = root->left;
root->val = tmp->val;
root->left = tmp->left;
root->right = tmp->right;
}
} else if (root->val < key) root->right = deleteNode(root->right, key);
else root->left = deleteNode(root->left, key);
return root;
}
};
116. Populating Next Right Pointers in Each Node
https://leetcode.com/problems/populating-next-right-pointers-in-each-node/description/
Given a binary tree struct TreeLinkNode {
TreeLinkNode *left;
TreeLinkNode *right;
TreeLinkNode *next;
}
Populate each next pointer to point to its next right node. If there is no next right node, the next pointer should be set to NULL. Initially, all next pointers are set to NULL. Note: You may only use constant extra space.
You may assume that it is a perfect binary tree (ie, all leaves are at the same level, and every parent has two children).
For example,
Given the following perfect binary tree, / \ / \ / \ After calling your function, the tree should look like:
-> NULL
/ \
-> -> NULL
/ \ / \
->->-> -> NULL
BFS。双queue实现的BFS空间复杂度为O(N),不满足要求。利用next指针可以实现BFS,空间复杂度仅为O(1)。BFS的思想:遍历本层,链接下一层并记录下一层的起始节点。
/**
* Definition for binary tree with next pointer.
* struct TreeLinkNode {
* int val;
* TreeLinkNode *left, *right, *next;
* TreeLinkNode(int x) : val(x), left(NULL), right(NULL), next(NULL) {}
* };
*/
class Solution {
public:
void connect(TreeLinkNode *root) {
if (!root) return;
queue<TreeLinkNode*> q, next;
q.push(root);
while (!q.empty()) {
while (!q.empty()) {
auto cur = q.front();
q.pop();
if (cur->left) next.push(cur->left);
if (cur->right) next.push(cur->right);
if (!q.empty()) cur->next = q.front();
}
swap(q, next);
}
}
};
/**
* Definition for binary tree with next pointer.
* struct TreeLinkNode {
* int val;
* TreeLinkNode *left, *right, *next;
* TreeLinkNode(int x) : val(x), left(NULL), right(NULL), next(NULL) {}
* };
*/
class Solution {
public:
void connect(TreeLinkNode *root) {
if (!root) return;
TreeLinkNode* levelStart = root;
while (levelStart) {
TreeLinkNode* cur = levelStart;
while (cur) {
if (cur->left) cur->left->next = cur->right;
if (cur->right && cur->next) cur->right->next = cur->next->left;
cur = cur->next;
}
levelStart = levelStart->left;
}
}
};
more-efficient
117. Populating Next Right Pointers in Each Node II
https://leetcode.com/problems/populating-next-right-pointers-in-each-node-ii/description/
Follow up for problem "Populating Next Right Pointers in Each Node". What if the given tree could be any binary tree? Would your previous solution still work? Note: You may only use constant extra space.
For example,
Given the following binary tree, / \ / \ \ After calling your function, the tree should look like:
-> NULL
/ \
-> -> NULL
/ \ \
-> -> -> NULL
BFS。同116。
/**
* Definition for binary tree with next pointer.
* struct TreeLinkNode {
* int val;
* TreeLinkNode *left, *right, *next;
* TreeLinkNode(int x) : val(x), left(NULL), right(NULL), next(NULL) {}
* };
*/
class Solution {
public:
void connect(TreeLinkNode *root) {
if (!root) return;
queue<TreeLinkNode*> q, next;
q.push(root);
while (!q.empty()) {
while(!q.empty()) {
auto cur = q.front();
q.pop();
if (cur->left) next.push(cur->left);
if (cur->right) next.push(cur->right);
if (!q.empty()) cur->next = q.front();
}
swap(q, next);
}
}
};
low-efficiency
/**
* Definition for binary tree with next pointer.
* struct TreeLinkNode {
* int val;
* TreeLinkNode *left, *right, *next;
* TreeLinkNode(int x) : val(x), left(NULL), right(NULL), next(NULL) {}
* };
*/
class Solution {
public:
void connect(TreeLinkNode *root) {
if (!root) return;
auto levelStart = root;
while () {
TreeLinkNode *cur = levelStart, *pre = NULL;
while (cur) {
if (cur->left) {
if (pre) pre->next = cur->left;
else levelStart = cur->left;
pre = cur->left;
}
if (cur->right) {
if (pre) pre->next = cur->right;
else levelStart = cur->right;
pre = cur->right;
}
cur = cur->next;
}
if (!pre) break;
}
}
};
more-efficient
236. Lowest Common Ancestor of a Binary Tree
https://leetcode.com/problems/lowest-common-ancestor-of-a-binary-tree/description/
Given a binary tree, find the lowest common ancestor (LCA) of two given nodes in the tree. According to the definition of LCA on Wikipedia: “The lowest common ancestor is defined between two nodes v and w as the lowest node in T that has both v and w as descendants (where we allow a node to be a descendant of itself).” _______3______
/ \
___5__ ___1__
/ \ / \
_2
/ \ For example, the lowest common ancestor (LCA) of nodes and is . Another example is LCA of nodes and is , since a node can be a descendant of itself according to the LCA definition.
LCA,非常经典,一次AC。O(N)时间复杂度,递归找path,选出最后一个相同节点。
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
private:
bool findPath(TreeNode* root, TreeNode* node, vector<TreeNode*>& path) {
if (!root) return false;
if (root == node) {
return true;
} else {
path.push_back(root->left);
if (findPath(root->left, node, path)) return true;
path.pop_back();
path.push_back(root->right);
if (findPath(root->right, node, path)) return true;
path.pop_back();
}
return false;
}
public:
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
vector<TreeNode*> path1(, root), path2(, root);
bool p_found = findPath(root, p, path1);
bool q_found = findPath(root, q, path2);
int l = min(path1.size(), path2.size());
TreeNode* res = NULL;
for (int i = ; i < l; i++) {
if (path1[i] == path2[i]) res = path1[i];
else break;
}
return res;
}
};
297. Serialize and Deserialize Binary Tree
https://leetcode.com/problems/serialize-and-deserialize-binary-tree/description/
Serialization is the process of converting a data structure or object into a sequence of bits so that it can be stored in a file or memory buffer, or transmitted across a network connection link to be reconstructed later in the same or another computer environment. Design an algorithm to serialize and deserialize a binary tree. There is no restriction on how your serialization/deserialization algorithm should work. You just need to ensure that a binary tree can be serialized to a string and this string can be deserialized to the original tree structure. For example, you may serialize the following tree / \ / \ as "[1,2,3,null,null,4,5]", just the same as how LeetCode OJ serializes a binary tree. You do not necessarily need to follow this format, so please be creative and come up with different approaches yourself.
Note: Do not use class member/global/static variables to store states. Your serialize and deserialize algorithms should be stateless.
树的序列化与反序列化,非常经典!先序遍历的递归。
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Codec {
private:
void serialize(TreeNode* root, ostringstream& out) {
if (!root) {
out << "# ";
return;
}
out << to_string(root->val) << " ";
serialize(root->left, out);
serialize(root->right, out);
} TreeNode* deserialize(istringstream& in) {
string s;
in >> s;
if (s == "#") return NULL;
TreeNode* root = new TreeNode(stoi(s));
root->left = deserialize(in);
root->right = deserialize(in);
return root;
} public: // Encodes a tree to a single string.
string serialize(TreeNode* root) {
ostringstream out;
serialize(root, out);
return out.str();
} // Decodes your encoded data to tree.
TreeNode* deserialize(string data) {
istringstream in(data);
return deserialize(in);
}
}; // Your Codec object will be instantiated and called as such:
// Codec codec;
// codec.deserialize(codec.serialize(root));
449. Serialize and Deserialize BST
https://leetcode.com/problems/serialize-and-deserialize-bst/description/
Serialization is the process of converting a data structure or object into a sequence of bits so that it can be stored in a file or memory buffer, or transmitted across a network connection link to be reconstructed later in the same or another computer environment. Design an algorithm to serialize and deserialize a binary search tree. There is no restriction on how your serialization/deserialization algorithm should work. You just need to ensure that a binary search tree can be serialized to a string and this string can be deserialized to the original tree structure. The encoded string should be as compact as possible. Note: Do not use class member/global/static variables to store states. Your serialize and deserialize algorithms should be stateless.
BST的序列化与反序列化,和上题使用完全相同的思路AC,应该可以结合BST的特征进行简化!
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Codec {
private:
void serialize(TreeNode* root, ostringstream& out) {
if (!root) {
out << "# ";
return;
}
out << to_string(root->val);
out << " ";
serialize(root->left, out);
serialize(root->right, out);
} TreeNode* deserialize(istringstream& in) {
string s;
in >> s;
if (s == "#") return NULL;
TreeNode* root = new TreeNode(stoi(s));
root->left = deserialize(in);
root->right = deserialize(in);
return root;
} public: // Encodes a tree to a single string.
string serialize(TreeNode* root) {
ostringstream out;
serialize(root, out);
return out.str();
} // Decodes your encoded data to tree.
TreeNode* deserialize(string data) {
istringstream in(data);
return deserialize(in);
}
}; // Your Codec object will be instantiated and called as such:
// Codec codec;
// codec.deserialize(codec.serialize(root));
652. Find Duplicate Subtrees
https://leetcode.com/problems/find-duplicate-subtrees/description/
Given a binary tree, return all duplicate subtrees. For each kind of duplicate subtrees, you only need to return the root node of any one of them. Two trees are duplicate if they have the same structure with same node values. Example : / \ / / \ / The following are two duplicate subtrees: / and Therefore, you need to return above trees' root in the form of a list.
利用树的遍历先进行序列化,在序列化过程中将序列化结果和根节点对应起来,注意树的序列化结果要有唯一性,必须加入额外信息:如两侧加括号。
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
private:
string serialize(TreeNode* root, map<string, vector< TreeNode* > >& m) {
if (!root) return "";
string s = "(" + serialize(root->left, m) + to_string(root->val) + serialize(root->right, m) + ")";
m[s].push_back(root);
return s;
}
public:
vector<TreeNode*> findDuplicateSubtrees(TreeNode* root) {
map<string, vector<TreeNode*>> m;
serialize(root, m);
vector<TreeNode*> res();
for (auto iter = m.begin(); iter != m.end(); iter++) {
if (iter->second.size() > ) res.push_back(iter->second[]);
}
return res;
}
};
752. Open the Lock
https://leetcode.com/contest/weekly-contest-64/problems/open-the-lock/
You have a lock in front of you with circular wheels. Each wheel has slots: '', '', '', '', '', '', '', '', '', ''. The wheels can rotate freely and wrap around: for example we can turn '' to be '', or '' to be ''. Each move consists of turning one wheel one slot. The lock initially starts at '', a string representing the state of the wheels. You are given a list of deadends dead ends, meaning if the lock displays any of these codes, the wheels of the lock will stop turning and you will be unable to open it. Given a target representing the value of the wheels that will unlock the lock, return the minimum total number of turns required to open the lock, or - if it is impossible. Example :
Input: deadends = ["","","","",""], target = ""
Output:
Explanation:
A sequence of valid moves would be "" -> "" -> "" -> "" -> "" -> "" -> "".
Note that a sequence like "" -> "" -> "" -> "" -> "" would be invalid,
because the wheels of the lock become stuck after the display becomes the dead end "".
Example :
Input: deadends = [""], target = ""
Output:
Explanation:
We can turn the last wheel in reverse to move from "" -> "".
Example :
Input: deadends = ["","","","","","","",""], target = ""
Output: -
Explanation:
We can't reach the target without getting stuck.
Example :
Input: deadends = [""], target = ""
Output: -
Note:
The length of deadends will be in the range [, ].
target will not be in the list deadends.
Every string in deadends and the string target will be a string of digits from the , possibilities '' to ''.
BFS,很简单,比赛的时候网站报的出问题case不对,出问题的原因是没有对"0000"这一状态进行检测就加入了队列,但是网站上给的提示case不是这个。感觉DP也能做。
class Solution {
public:
int openLock(vector<string>& deadends, string target) {
queue<string> q, next;
map<string, int> dis;
for (string e : deadends) dis[e] = -;
if (dis[""] < ) return -;
q.push(""); dis[""] = ;
int layer = ;
while (!q.empty()) {
while (!q.empty()) {
string cur = q.front(); q.pop();
for (int i = ; i < ; i++) {
for (int j = -; j < ; j += ) {
string tmp(cur);
tmp[i] += j;
if (tmp[i] > '') tmp[i] -= ;
if (tmp[i] < '') tmp[i] += ;
if (tmp == target) return layer;
if (dis[tmp] == && tmp != "") {
next.push(tmp);
dis[tmp] = layer;
}
}
}
}
swap(q, next);
layer++;
}
return target == "" ? : -;
}
};
747. Largest Number Greater Than Twice of Others
https://leetcode.com/contest/weekly-contest-64/problems/largest-number-greater-than-twice-of-others/
In a given integer array nums, there is always exactly one largest element. Find whether the largest element in the array is at least twice as much as every other number in the array. If it is, return the index of the largest element, otherwise return -. Example :
Input: nums = [, , , ]
Output:
Explanation: is the largest integer, and for every other number in the array x,
is more than twice as big as x. The index of value is , so we return .
Example :
Input: nums = [, , , ]
Output: -
Explanation: isn't at least as big as twice the value of 3, so we return -1.
Note:
nums will have a length in the range [, ].
Every nums[i] will be an integer in the range [, ].
Discuss
数组最大值,简单题
class Solution {
public:
int dominantIndex(vector<int>& nums) {
int s = nums.size();
if (s == ) return -;
int max_index = ;
for (int i = ; i < nums.size(); i++) {
max_index = nums[i] > nums[max_index] ? i : max_index;
}
int c = ;
for (int n : nums) {
if (nums[max_index] / >= n) c++;
}
return c >= s - ? max_index : -;
}
};
491. Increasing Subsequences
https://leetcode.com/problems/increasing-subsequences/description/
Given an integer array, your task is to find all the different possible increasing subsequences of the given array, and the length of an increasing subsequence should be at least . Example:
Input: [, , , ]
Output: [[, ], [, ], [, , ], [, , , ], [, ], [, , ], [,], [,,]]
Note:
The length of the given array will not exceed .
The range of integer in the given array is [-,].
The given array may contain duplicates, and two equal integers should also be considered as a special case of increasing sequence.
dfs,有点小trick,去重时要遍历之前的所有元素,查看是否有重复,因为题目不允许sort。
class Solution {
private:
void dfs(const vector<int>& nums, vector<vector<int>>& res, vector<int>& path, int start) {
if (start >= nums.size()) return;
for (int i = start; i < nums.size(); i++) {
int dup = start;
while (dup < i && nums[dup] != nums[i]) dup++;
if (dup != i) continue;
if (path.size() == || nums[i] >= path.back()) {
path.push_back(nums[i]);
if (path.size() > ) res.push_back(path);
dfs(nums, res, path, i + );
path.pop_back();
}
}
}
public:
vector<vector<int>> findSubsequences(vector<int>& nums) {
vector<vector<int>> res(, vector<int> ());
int n = nums.size();
if (n < ) {
return res;
}
vector<int> path;
dfs(nums, res, path, );
return res;
}
};
284. Peeking Iterator
https://leetcode.com/problems/peeking-iterator/description/
Given an Iterator class interface with methods: next() and hasNext(), design and implement a PeekingIterator that support the peek() operation -- it essentially peek() at the element that will be returned by the next call to next(). Here is an example. Assume that the iterator is initialized to the beginning of the list: [, , ]. Call next() gets you , the first element in the list. Now you call peek() and it returns , the next element. Calling next() after that still return . You call next() the final time and it returns , the last element. Calling hasNext() after that should return false. Follow up: How would you extend your design to be generic and work with all types, not just integer?
考的是拷贝构造函数的应用。
// Below is the interface for Iterator, which is already defined for you.
// **DO NOT** modify the interface for Iterator.
class Iterator {
struct Data;
Data* data;
public:
Iterator(const vector<int>& nums);
Iterator(const Iterator& iter);
virtual ~Iterator();
// Returns the next element in the iteration.
int next();
// Returns true if the iteration has more elements.
bool hasNext() const;
}; class PeekingIterator : public Iterator {
public:
PeekingIterator(const vector<int>& nums) : Iterator(nums) {
// Initialize any member here.
// **DO NOT** save a copy of nums and manipulate it directly.
// You should only use the Iterator interface methods.
} // Returns the next element in the iteration without advancing the iterator.
int peek() {
return Iterator(*this).next();
} // hasNext() and next() should behave the same as in the Iterator interface.
// Override them if needed.
int next() {
return Iterator::next();
} bool hasNext() const {
return Iterator::hasNext();
}
};
208. Implement Trie (Prefix Tree)
https://leetcode.com/problems/implement-trie-prefix-tree/description/
Implement a trie with insert, search, and startsWith methods. Note:
You may assume that all inputs are consist of lowercase letters a-z.
Trie。实现Trie。注意要用c - 'a'而不是直接用c来索引后继节点!
class Trie {
public:
class Node{
public:
bool end;
vector<Node*> next;
Node() {
end = false;
next.resize(, NULL);
}
};
Node* root;
/** Initialize your data structure here. */
Trie() {
root = new Node();
} /** Inserts a word into the trie. */
void insert(string word) {
Node* tmp = root;
for (char c : word) {
if (!tmp->next[c - 'a']) tmp->next[c - 'a'] = new Node();
tmp = tmp->next[c - 'a'];
}
tmp->end = true;
} /** Returns if the word is in the trie. */
bool search(string word) {
Node* tmp = root;
for (char c: word) {
if (!tmp->next[c - 'a']) return false;
tmp = tmp->next[c - 'a'];
}
return tmp->end;
} /** Returns if there is any word in the trie that starts with the given prefix. */
bool startsWith(string prefix) {
Node* tmp = root;
for (char c : prefix) {
if (!tmp->next[c - 'a']) return false;
tmp = tmp->next[c - 'a'];
}
return true;
}
};
/**
* Your Trie object will be instantiated and called as such:
* Trie obj = new Trie();
* obj.insert(word);
* bool param_2 = obj.search(word);
* bool param_3 = obj.startsWith(prefix);
*/
14. Longest Common Prefix
https://leetcode.com/problems/longest-common-prefix/description/
Trie。找一个字符串数组的最长公共前缀,建一个Trie即可。
class Node {
public:
bool end;
vector<Node*> next;
Node() {
end = false;
next.resize(, NULL);
}
}; class Solution {
public:
string longestCommonPrefix(vector<string>& strs) {
Node *root = new Node();
for (string s : strs) {
auto tmp = root;
for (char c : s) {
if (!tmp->next[c]) tmp->next[c] = new Node();
tmp = tmp->next[c];
}
tmp->end = true;
}
string res = "";
while (root && !root->end) {
int next = -;
for (int i = ; i < ; i++) {
if (root->next[i]) {
if (next >= ) return res;
next = i;
}
}
if (next >= ) res += char(next);
root = next >= ? root->next[next] : NULL;
}
return res;
}
};
648. Replace Words
https://leetcode.com/problems/replace-words/description/
In English, we have a concept called root, which can be followed by some other words to form another longer word - let's call this word successor. For example, the root an, followed by other, which can form another word another. Now, given a dictionary consisting of many roots and a sentence. You need to replace all the successor in the sentence with the root forming it. If a successor has many roots can form it, replace it with the root with the shortest length. You need to output the sentence after the replacement. Example :
Input: dict = ["cat", "bat", "rat"]
sentence = "the cattle was rattled by the battery"
Output: "the cat was rat by the bat"
Note:
The input will only have lower-case letters.
<= dict words number <=
<= sentence words number <=
<= root length <=
<= sentence words length <=
Trie
class Solution {
public:
class Node{
public:
bool end;
vector<Node*> next;
Node() {
end = false;
next.resize(, NULL);
}
};
Node* root = new Node();
string replaceWords(vector<string>& dict, string sentence) {
for (string s : dict) {
Node* tmp = root;
for (char c : s) {
if (!tmp->next[c - 'a']) tmp->next[c - 'a'] = new Node();
tmp = tmp->next[c - 'a'];
}
tmp->end = true;
}
istringstream ss(sentence);
string buffer, res;
while (getline(ss, buffer, ' ')) {
string path = "";
Node* tmp = root;
bool finded = false;
for (char c : buffer) {
if (!tmp) break;
if (tmp->end) {
finded = true;
break;
}
tmp = tmp->next[c - 'a'];
}
if (!finded) res += buffer + " ";
else {
tmp = root;
for (char c : buffer) {
if (!tmp || tmp->end) break;
path.push_back(c);
tmp = tmp->next[c - 'a'];
}
res += path + " ";
}
}
res.pop_back();
return res;
}
};
307. Range Sum Query - Mutable
https://leetcode.com/problems/range-sum-query-mutable/description/
Given an integer array nums, find the sum of the elements between indices i and j (i ≤ j), inclusive. The update(i, val) function modifies nums by updating the element at index i to val.
Example:
Given nums = [, , ] sumRange(, ) ->
update(, )
sumRange(, ) ->
Note:
The array is only modifiable by the update function.
You may assume the number of calls to update and sumRange function is distributed evenly.
一刷使用暴力解法AC,时间复杂度为O(N)。用线段树和二分索引树做时间复杂度可以降到O(log N)。
class NumArray {
private:
vector<int> v;
public:
NumArray(vector<int> nums) {
v = nums;
} void update(int i, int val) {
v[i] = val;
} int sumRange(int i, int j) {
int sum = ;
for (int k = i; k <= j; k++) sum += v[k];
return sum;
}
}; /**
* Your NumArray object will be instantiated and called as such:
* NumArray obj = new NumArray(nums);
* obj.update(i,val);
* int param_2 = obj.sumRange(i,j);
*/
brute_force
530. Minimum Absolute Difference in BST
https://leetcode.com/problems/minimum-absolute-difference-in-bst/description/
Given a binary search tree with non-negative values, find the minimum absolute difference between values of any two nodes. Example: Input: \ / Output: Explanation:
The minimum absolute difference is , which is the difference between and (or between and ).
Note: There are at least two nodes in this BST.
一刷递归一次AC。
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
int getMinimumDifference(TreeNode* root) {
int res = INT_MAX;
if (!root) return res;
if (root->left) {
auto tmp = root->left;
while (tmp->right) tmp = tmp->right;
res = min(res, root->val - tmp->val);
}
if (root->right) {
auto tmp = root->right;
while (tmp->left) tmp = tmp->left;
res = min(res, tmp->val - root->val);
}
int left_res = getMinimumDifference(root->left);
int right_res = getMinimumDifference(root->right);
return min(res, min(left_res, right_res));
}
};
729. My Calendar I
https://leetcode.com/problems/my-calendar-i/description/
Implement a MyCalendar class to store your events. A new event can be added if adding the event will not cause a double booking. Your class will have the method, book(int start, int end). Formally, this represents a booking on the half open interval [start, end), the range of real numbers x such that start <= x < end. A double booking happens when two events have some non-empty intersection (ie., there is some time that is common to both events.) For each call to the method MyCalendar.book, return true if the event can be added to the calendar successfully without causing a double booking. Otherwise, return false and do not add the event to the calendar. Your class will be called like this: MyCalendar cal = new MyCalendar(); MyCalendar.book(start, end)
Example :
MyCalendar();
MyCalendar.book(, ); // returns true
MyCalendar.book(, ); // returns false
MyCalendar.book(, ); // returns true
Explanation:
The first event can be booked. The second can't because time 15 is already booked by another event.
The third event can be booked, as the first event takes every time less than , but not including .
Note: The number of calls to MyCalendar.book per test case will be at most .
In calls to MyCalendar.book(start, end), start and end are integers in the range [, ^].
线段交集,感觉跟线段树或者二分索引书有关,不清楚!要继续思考,一刷AC。
class MyCalendar {
public:
vector<pair<int, int>> books;
MyCalendar() { } bool book(int start, int end) {
for (auto p : books) {
if (max(p.first, start) < min(p.second, end)) return false;
}
books.push_back({start, end});
return true;
}
}; /**
* Your MyCalendar object will be instantiated and called as such:
* MyCalendar obj = new MyCalendar();
* bool param_1 = obj.book(start,end);
*/
731. My Calendar II
https://leetcode.com/problems/my-calendar-ii/description/
Implement a MyCalendarTwo class to store your events. A new event can be added if adding the event will not cause a triple booking. Your class will have one method, book(int start, int end). Formally, this represents a booking on the half open interval [start, end), the range of real numbers x such that start <= x < end. A triple booking happens when three events have some non-empty intersection (ie., there is some time that is common to all events.) For each call to the method MyCalendar.book, return true if the event can be added to the calendar successfully without causing a triple booking. Otherwise, return false and do not add the event to the calendar. Your class will be called like this: MyCalendar cal = new MyCalendar(); MyCalendar.book(start, end)
Example :
MyCalendar();
MyCalendar.book(, ); // returns true
MyCalendar.book(, ); // returns true
MyCalendar.book(, ); // returns true
MyCalendar.book(, ); // returns false
MyCalendar.book(, ); // returns true
MyCalendar.book(, ); // returns true
Explanation:
The first two events can be booked. The third event can be double booked.
The fourth event (, ) can't be booked, because it would result in a triple booking.
The fifth event (, ) can be booked, as it does not use time which is already double booked.
The sixth event (, ) can be booked, as the time in [, ) will be double booked with the third event;
the time [, ) will be single booked, and the time [, ) will be double booked with the second event.
Note: The number of calls to MyCalendar.book per test case will be at most .
In calls to MyCalendar.book(start, end), start and end are integers in the range [, ^].
这是一道什么类型的题?还有什么其他方法?这类interval的题目还是比较多的。一刷使用逐一重叠并记录的方法。
class MyCalendarTwo {
public:
class MyCalendar{
public:
vector<pair<int, int>> books;
MyCalendar() {}
bool book(int s, int e) {
for (auto p : books) {
if (max(s, p.first) < min(e, p.second)) return false;
}
books.push_back({s, e});
return true;
}
}; vector<pair<int, int>> books;
MyCalendarTwo() { } bool book(int start, int end) {
MyCalendar overlaps;
for (auto p : books) {
if (max(p.first, start) < min(p.second, end)) {
if (!overlaps.book(max(p.first, start), min(p.second, end))) return false;
}
}
books.push_back({start, end});
return true;
}
}; /**
* Your MyCalendarTwo object will be instantiated and called as such:
* MyCalendarTwo obj = new MyCalendarTwo();
* bool param_1 = obj.book(start,end);
*/
220. Contains Duplicate III
https://leetcode.com/problems/contains-duplicate-iii/description/
Given an array of integers, find out whether there are two distinct indices i and j in the array such that the absolute difference between nums[i] and nums[j] is at most t and the absolute difference between i and j is at most k.
一刷暴力法,O(NK)的时间复杂度,TLE。二刷使用基于bucket的方法AC。
class Solution {
public:
bool containsNearbyAlmostDuplicate(vector<int>& nums, int k, int t) {
int s = nums.size();
if (s < ) return false;
long long a, b;
for (int i = ; i < s; i++) {
for (int j = i + ; j < s && j <= i + k; j++) {
a = nums[i], b = nums[j];
if (abs(a - b) <= t) return true;
}
}
return false;
}
};
brute_force
class Solution {
public:
bool containsNearbyAlmostDuplicate(vector<int>& nums, int k, int t) {
map<long long, long long> m;
int s = nums.size();
if (t < || s < || k < ) return false;
for (int i = ; i < s; i++) {
long long a = nums[i], tmp = t;
a -= INT_MAX;
long long bucket = a / (tmp + );
if (m.find(bucket) != m.end() ||
(m.find(bucket - ) != m.end() && a - m[bucket - ] <= t) ||
(m.find(bucket + ) != m.end() && m[bucket + ] - a <= t)) return true;
if (m.size() >= k) {
long long last_num = nums[i - k];
m.erase((last_num - INT_MAX) / (tmp + ));
}
m[bucket] = a;
}
return false;
}
};
bucket
382. Linked List Random Node
https://leetcode.com/problems/linked-list-random-node/description/
Given a singly linked list, return a random node's value from the linked list. Each node must have the same probability of being chosen. Follow up:
What if the linked list is extremely large and its length is unknown to you? Could you solve this efficiently without using extra space? Example: // Init a singly linked list [1,2,3].
ListNode head = new ListNode();
head.next = new ListNode();
head.next.next = new ListNode();
Solution solution = new Solution(head); // getRandom() should return either 1, 2, or 3 randomly. Each element should have equal probability of returning.
solution.getRandom();
概率,math。for循环每次以1/k概率将原值覆盖,(1-1/k)的概率保留原值。当链表中的数字为:{1, 2, 3, 4}时,概率分布如下:
P(res = 1) = 1 * 1/2 * 2/3 * 3/4
P(res = 2) = 1/2 * 2/3 * 3/4
P(res = 3) = 1/3 * 3/4
P(res = 4) = 1/4
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
/** @param head The linked list's head.
Note that the head is guaranteed to be not null, so it contains at least one node. */
ListNode* h;
Solution(ListNode* head) {
h = head;
} /** Returns a random node's value. */
int getRandom() {
int count = , res;
ListNode* tmp = h;
while (tmp) {
if (rand() % count == ) res = tmp->val;
tmp = tmp->next;
count++;
}
return res;
}
}; /**
* Your Solution object will be instantiated and called as such:
* Solution obj = new Solution(head);
* int param_1 = obj.getRandom();
*/
398. Random Pick Index
https://leetcode.com/problems/random-pick-index/description/
Given an array of integers with possible duplicates, randomly output the index of a given target number. You can assume that the given target number must exist in the array. Note:
The array size can be very large. Solution that uses too much extra space will not pass the judge. Example: int[] nums = new int[] {,,,,};
Solution solution = new Solution(nums); // pick(3) should return either index 2, 3, or 4 randomly. Each index should have equal probability of returning.
solution.pick(); // pick(1) should return 0. Since in the array only nums[0] is equal to 1.
solution.pick();
同上一题。
class Solution {
private:
vector<int> _nums;
public:
Solution(vector<int> nums) {
_nums = nums;
} int pick(int target) {
int n = , res;
for (int i = ; i < _nums.size(); i++) {
if (_nums[i] != target) continue;
n++;
if (rand() % n == ) res = i;
}
return res;
}
}; /**
* Your Solution object will be instantiated and called as such:
* Solution obj = new Solution(nums);
* int param_1 = obj.pick(target);
*/
560. Subarray Sum Equals K
https://leetcode.com/problems/subarray-sum-equals-k/description/
Given an array of integers and an integer k, you need to find the total number of continuous subarrays whose sum equals to k. Example :
Input:nums = [,,], k =
Output:
Note:
The length of the array is in range [, ,].
The range of numbers in the array is [-, ] and the range of the integer k is [-1e7, 1e7].
一刷使用二维DP内存超了,改为一维DP之后AC,这两种方法都是O(N^2)时间复杂度,空间复杂度一个为O(N^2),一个为O(N)。二刷三刷用map存储累积和,map的查找替换了vector的查找,时间复杂度从O(N^2)降到了O(N)。仍然不太理解初始时"m[0]=1"的设置!
class Solution {
public:
int subarraySum(vector<int>& nums, int k) {
int n = nums.size(), res = ;
if (n < ) return res;
vector<int> dp(n, );
for (int i = ; i < n; i++) {
dp[i] = nums[i];
if (dp[i] == k) res++;
for (int j = i + ; j < n; j++) {
dp[j] = dp[j - ] + nums[j];
if (dp[j] == k) res++;
}
}
return res;
}
};
1d-DP
class Solution {
public:
int subarraySum(vector<int>& nums, int k) {
map<int, int> m;
int res = , sum = ;
m[]++;
for (int n : nums) {
sum += n;
res += m[sum - k];
m[sum]++;
}
return res;
}
};
map
760. Find Anagram Mappings
https://leetcode.com/contest/weekly-contest-66/problems/find-anagram-mappings/
Given two lists Aand B, and B is an anagram of A. B is an anagram of A means B is made by randomizing the order of the elements in A. We want to find an index mapping P, from A to B. A mapping P[i] = j means the ith element in A appears in B at index j. These lists A and B may contain duplicates. If there are multiple answers, output any of them. For example, given A = [, , , , ]
B = [, , , , ]
We should return
[, , , , ]
as P[] = because the 0th element of A appears at B[], and P[] = because the 1st element of A appears at B[], and so on.
Note: A, B have equal lengths in range [, ].
A[i], B[i] are integers in range [, ^].
map,key为元素值,value为vector的iterator。
class Solution {
public:
vector<int> anagramMappings(vector<int>& A, vector<int>& B) {
vector<int> res();
int s = A.size();
if (s < ) return res;
res.resize(s, );
map<int, vector<int>::iterator> m;
for (int i = ; i < A.size(); i++) {
if (m.find(A[i]) == m.end()) m[A[i]] = B.begin();
auto iter = find(m[A[i]], B.end(), A[i]);
res[i] = iter - B.begin();
m[A[i]] = iter + ;
}
return res;
}
};
758. Bold Words in String
https://leetcode.com/contest/weekly-contest-66/problems/bold-words-in-string/
Given a set of keywords words and a string S, make all appearances of all keywords in S bold. Any letters between <b> and </b> tags become bold. The returned string should use the least number of tags possible, and of course the tags should form a valid combination. For example, given that words = ["ab", "bc"] and S = "aabcd", we should return "a<b>abc</b>d". Note that returning "a<b>a<b>b</b>c</b>d" would use more tags, so it is incorrect. Note: words has length in range [, ].
words[i] has length in range [, ].
S has length in range [, ].
All characters in words[i] and S are lowercase letters.
转化为合并interval
class Solution {
public:
string boldWords(vector<string>& words, string S) {
vector<pair<int, int>> intervals;
for (auto key : words) {
int pos = ;
while (pos < S.size()) {
int p = S.find(key, pos);
if (p == string::npos) break;
else{
pos++;
intervals.push_back({p, p + key.size()});
}
}
}
if (intervals.size() == ) return S;
sort(intervals.begin(), intervals.end(), myCompare);
vector<pair<int, int>> res(, intervals[]);
for (auto p : intervals) {
if (p.first <= res.back().second) res.back().second = max(p.second, res.back().second);
else res.push_back(p);
}
string s1 = "<b>", s2 = "</b>", s;
int last = ;
for (auto p : res) {
s += S.substr(last, p.first - last);
s += s1;
s += S.substr(p.first, p.second - p.first);
s += s2;
last = p.second;
}
s += S.substr(last, S.size() - last);
return s;
} static bool myCompare(pair<int, int>& a, pair<int, int>& b) {
return a.first < b.first;
}
};
759. Employee Free Time
https://leetcode.com/contest/weekly-contest-66/problems/employee-free-time/
We are given a list avail of employees, which represents the free time for each employee. Each employee has a list of non-overlapping Intervals, and these intervals are in sorted order. Return the list of finite intervals representing common, positive-length free time for all employees, also in sorted order. Example :
Input: avails = [[[,],[,]],[[,]],[[,]]]
Output: [[,]]
Explanation:
There are a total of three employees, and all common
free time intervals would be [-inf, ], [, ], [, inf].
We discard any intervals that contain inf as they aren't finite.
Example :
Input: avails = [[[,],[,]],[[,]],[[,],[,]]]
Output: [[,],[,]]
(Even though we are representing Intervals in the form [x, y], the objects inside are Intervals, not lists or arrays. For example, avails[][].start = , avails[][].end = , and avails[][][] is not defined.) Also, we wouldn't include intervals like [5, 5] in our answer, as they have zero length. Note: avails and avails[i] are lists with lengths in range [, ].
<= avails[i].start < avails[i].end <= ^.
同上题,转化为合并interval。
/**
* Definition for an interval.
* struct Interval {
* int start;
* int end;
* Interval() : start(0), end(0) {}
* Interval(int s, int e) : start(s), end(e) {}
* };
*/
class Solution {
public:
vector<Interval> employeeFreeTime(vector<vector<Interval>>& avails) {
vector<Interval> res();
vector<Interval> intervals;
for (auto v : avails) {
for (auto i : v) intervals.push_back(i);
}
if (intervals.size() == ) return res;
sort(intervals.begin(), intervals.end(), myCompare);
vector<Interval> c(, intervals[]);
for (auto i : intervals) {
if (i.start <= c.back().end) c.back().end = max(c.back().end, i.end);
else c.push_back(i);
}
for (int i = ; i < c.size(); i++) res.push_back(Interval(c[i - ].end, c[i].start));
return res;
}
static bool myCompare(Interval& a, Interval& b) {
return a.start < b.start;
}
};
28. Implement strStr()
https://leetcode.com/problems/implement-strstr/description/
暴力匹配和KMP算法,KMP算法关键在于求解next数组。求解next数组和模式匹配过程相似,只是求解过程需要修改next数组。
class Solution {
private:
void get_next(vector<int>& v, const string& str) {
int i = , j = -;
v[i] = j;
while (i < str.size() - ) {
if (j == - || str[i] == str[j]) v[++i] = ++j;
else j = v[j];
}
}
public:
int strStr(string haystack, string needle) {
int m = haystack.size(), n = needle.size();
if (n == ) return ;
if (m == ) return -;
vector<int> next(n, );
get_next(next, needle);
int i = , j = ;
while (i < m && j < n) {
if (j == - || haystack[i] == needle[j]) {
i++; j++;
} else j = next[j];
}
return j == needle.size() ? i - j : -;
}
};
KMP
class Solution {
public:
int strStr(string haystack, string needle) {
int m = haystack.size(), n = needle.size();
if (n == ) return ;
for (int i = , j = ; i < m; i++) {
for (j = ; j < n; j++) {
if (haystack[i + j] != needle[j]) break;
}
if (j == n) return i;
}
return -;
}
};
brute force
762. Prime Number of Set Bits in Binary Representation
给定一个范围,判断范围内的每个数的二进制表示中1的个数是否为质数
bitset
class Solution {
public:
int countPrimeSetBits(int L, int R) {
set<int> primes = {, , , , , , , , , , };
int res = ;
for (int i = L; i <= R; i++) {
bitset<> b(i);
if (primes.find(b.count()) != primes.end()) res++;
}
return res;
}
};
763. Partition Labels
将仅含有小写字母的字符串,要求划分后子串尽可能多而且每个字母最多出现在一个划分中。
DFS超时,贪心AC。
class Solution {
public:
vector<int> partitionLabels(string S) {
vector<int> res;
if (S.size() == ) return res;
vector<pair<int, int>> pos(, {-, -});
for (int i = ; i < S.size(); i++) {
int v = S[i] - 'a';
if (pos[v].first == -) pos[v].first = i;
else pos[v].second = max(pos[v].second, i);
}
for (int i = ; i < ; i++) pos[i].second = max(pos[i].first, pos[i].second);
int pre = , stop = ;
while (pre < S.size()) {
stop = max(stop, pos[S[pre] - 'a'].second);
int l = ;
while (pre < S.size() && pre <= stop) {
l++;
stop = max(stop, pos[S[pre] - 'a'].second);
pre++;
}
res.push_back(l);
}
return res;
}
};
greedy
764. Largest Plus Sign
判断仅含有0和1的矩阵中,1的位置能够组成的最大“十字架”的形状大小。
DP。
class Solution {
public:
int orderOfLargestPlusSign(int N, vector<vector<int>>& mines) {
vector<vector<int>> m(N, vector<int> (N, ));
for (auto v: mines) m[v[]][v[]] = ;
vector<vector<int>> l(N, vector<int>(N, )), r = l, d = l, u = l;
for (int i = ; i < N; i++) {
for (int j = ; j < N; j++) {
if (m[i][j]) {
l[i][j] = j == ? : + l[i][j - ];
u[i][j] = i == ? : + u[i - ][j];
}
}
}
int ans = ;
for (int i = N - ; i >= ; i--) {
for (int j = N - ; j >= ; j--) {
if (m[i][j]) {
r[i][j] = j == N - ? : + r[i][j + ];
d[i][j] = i == N - ? : + d[i + ][j];
ans = max(ans, min(l[i][j], min(r[i][j], min(u[i][j], d[i][j]))));
}
}
}
return ans;
}
};
dp
65. Valid Number
https://leetcode.com/problems/valid-number/description/
正则表达式,注意trim之后再进行正则表达式匹配。
bool isNumber(string s) {
int i = , j = s.size();
if (j == ) return false;
for (; s[i] == ' '; i++);
for (j--; s[j] == ' '; j--);
s = s.substr(i, j - i + );
regex e("^([\\+\\-])?((\\d+(\\.\\d*)?)|(\\.\\d+))(e([\\+\\-]?\\d+))?$");
return regex_match(s.begin(), s.end(), e);
}
RE
70. Climbing Stairs
https://leetcode.com/problems/climbing-stairs/description/
斐波那契数列,DP和递归均可。递归超时,可以使用迭代替换递归
class Solution {
public:
int climbStairs(int n) {
if (n == ) return ;
if (n == ) return ;
vector<int> dp(n + , );
dp[] = ;
dp[] = ;
for (int i = ; i <= n; i++) dp[i] = dp[i - ] + dp[i - ];
return dp[n];
}
};
dp
class Solution {
public:
int climbStairs(int n) {
if (n == ) return ;
if (n == ) return ;
int pre1 = , pre2 = , cur = ;
for (int i = ; i <= n; i++) {
cur = pre1 + pre2;
pre1 = pre2;
pre2 = cur;
}
return cur;
}
};
iterative recursion
88. Merge Sorted Array
https://leetcode.com/problems/merge-sorted-array/description/
合并两个排好序的数组。我用了堆,用了temp,空间复杂度过高。最优解是将较长的数组扩充,然后倒着插入,思路类似快排,挖坑填坑。
class Solution {
public:
void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {
int i = m - , j = n - , cur = m + n - ;
while (j >= ) nums1[cur--] = (i >= && nums1[i] > nums2[j]) ? nums1[i--] : nums2[j--];
}
};
125. Valid Palindrome
https://leetcode.com/problems/valid-palindrome/description/
字符相关API如:isdigit,isalpha,isalnum,isupper,islower要用熟。
class Solution {
public:
bool isPalindrome(string s) {
int l = s.size(), b = , e = l - ;
while (b < e) {
while (!isalnum(s[b])) b++;
while (!isalnum(s[e])) e--;
if (isupper(s[b])) s[b] += 'a' - 'A';
if (isupper(s[e])) s[e] += 'a' - 'A';
if (b < e && s[b] != s[e]) return false;
b++; e--;
}
return true;
}
};
4. Median of Two Sorted Arrays
https://leetcode.com/problems/median-of-two-sorted-arrays/description/
二分查找。查找两个有序数组总的中位数,要求O(log(m+n))的时间复杂度。基于归并排序的方式O(m+n)的复杂度,基于递归的二分查找可以达到复杂度要求。
class Solution {
public:
double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
if (nums1.size() < nums2.size()) swap(nums1, nums2);
int l1 = nums1.size(), l2 = nums2.size();
if (l1 + l2 == ) return ;
nums1.resize(l1 + l2, );
bool flag = (l1 + l2) % ;
int limit = flag ? (l1 + l2) / : (l1 + l2) / - ;
for (int i = l1 + l2 - ; i >= limit; i--) {
while (l2 > && i >= limit) nums1[i--] = (nums1[l1- ] > nums2[l2 - ]) ? nums1[--l1] : nums2[--l2];
}
return flag ? nums1[limit] : ((double)nums1[limit] + nums1[limit + ]) / ;
}
};
merge_sort
class Solution {
public:
double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
int s1 = nums1.size(), s2 = nums2.size();
int l = (s1 + s2 + ) >> , r = (s1 + s2 + ) >> ;
return (getKth(nums1, , s1, nums2, , s2, l) + getKth(nums1, , s1, nums2, , s2, r)) / 2.0;
}
int getKth(vector<int>& l, int ls, int le, vector<int>& s, int ss, int se, int k) {
if (le - ls < se - ss) return getKth(s, ss, se, l, ls, le, k);
if (se == ss) return l[ls + k - ];
if (k == ) return min(l[ls], s[ss]);
int i = min(ls + k / , le), j = min(ss + k / , se);
if (l[i - ] > s[j - ]) return getKth(l, ls, le, s, j, se, k + ss - j);
else return getKth(l, i, le, s, ss, se, k + ls - i);
return ;
}
};
recursion
10. Regular Expression Matching
https://leetcode.com/problems/regular-expression-matching/description/
Implement regular expression matching with support for '.' and '*'. '.' Matches any single character.
'*' Matches zero or more of the preceding element. The matching should cover the entire input string (not partial). The function prototype should be:
bool isMatch(const char *s, const char *p) Some examples:
isMatch("aa","a") → false
isMatch("aa","aa") → true
isMatch("aaa","aa") → false
isMatch("aa", "a*") → true
isMatch("aa", ".*") → true
isMatch("ab", ".*") → true
isMatch("aab", "c*a*b") → true
正则表达式匹配,频率超高!同频的还有四则运算表达式的计算,前、中、后缀表达式切换和运算!
递归方法分char和‘.’,之后在内部讨论后面是否有'*'。DP考虑是否为'*',是'*'分不重复和重复,重复时'x*x'只需判断s把x去掉之后的情况,不是'*'可以归于一类。
class Solution {
public:
bool isMatch(string s, string p) {
int sl = s.size(), ps = p.size();
return isMatch(s, , p, );
}
bool isMatch(string& s, int spos, string& p, int ppos) {
if (ppos == p.size() && spos == s.size()) return true;
if (ppos >= p.size() || spos > s.size()) return false;
if (p[ppos] == '.') {
if (ppos + < p.size() && p[ppos + ] == '*') {
for (int i = spos; i <= s.size(); i++) {
if (isMatch(s, i, p, ppos + )) return true;
}
} else return isMatch(s, spos + , p, ppos + );
} else if (p[ppos] != '*') {
if (ppos + < p.size() && p[ppos + ] == '*') {
if (isMatch(s, spos, p, ppos + )) return true;
for (int i = spos; i < s.size() && s[i] == p[ppos]; i++){
if (isMatch(s, i + , p, ppos + )) return true;
}
} else return s[spos] == p[ppos] && isMatch(s, spos + , p, ppos + );
}
return false;
}
};
recursion
class Solution {
public:
bool isMatch(string s, string p) {
int ss = s.size(), ps = p.size();
vector<vector<bool>> dp(ss + , vector<bool>(ps + , false));
dp[][] = true;
for (int j = ; j <= ps; j++) dp[][j] = j > && p[j - ] == '*' && dp[][j - ];
for (int i = ; i <= ss; i++) {
for (int j = ; j <= ps; j++) {
if (p[j - ] == '*') dp[i][j] = dp[i][j - ] || ((s[i - ] == p[j - ] || p[j - ] == '.') && dp[i - ][j]);
else dp[i][j] = dp[i - ][j - ] && (s[i - ] == p[j - ] || p[j - ] == '.');
}
}
return dp[ss][ps];
}
};
dp
44. Wildcard Matching
https://leetcode.com/problems/wildcard-matching/description/
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). The function prototype should be:
bool isMatch(const char *s, const char *p) Some examples:
isMatch("aa","a") → false
isMatch("aa","aa") → true
isMatch("aaa","aa") → false
isMatch("aa", "*") → true
isMatch("aa", "a*") → true
isMatch("ab", "?*") → true
isMatch("aab", "c*a*b") → false
递归超时,DP可以AC。和10非常相似。还有更简单的方法及双指针法, https://yucoding.blogspot.com/2013/02/leetcode-question-123-wildcard-matching.html
class Solution {
public:
bool isMatch(string s, string p) {
int ss = s.size(), ps = p.size();
if (ps == ) return ss == ;
vector<vector<bool>> dp(ss + , vector<bool>(ps + , false));
dp[][] = true;
for (int i = ; i < ps; i++) {
if (p[i] == '*') {
for (int j = ; j <= ss; j++) {
if (dp[j][i]) {
dp[j][i + ] = true;
for (int k = j; k < ss; k++) dp[k + ][i + ] = true;
}
}
}
if (p[i] == '?') {
for (int j = ; j < ss; j++) {
if (dp[j][i]) dp[j + ][i + ] = true;
} } else {
for (int j = ; j < ss; j++) {
if (s[j] == p[i] && dp[j][i]) dp[j + ][i + ] = true;
}
}
}
return dp[ss][ps];
}
};
class Solution {
public:
bool isMatch(const char *s, const char *p) {
const char* star=NULL;
const char* ss=s;
while (*s){
if ((*p=='?')||(*p==*s)){s++;p++;continue;}
if (*p=='*'){star=p++; ss=s;continue;}
if (star){ p = star+; s=++ss;continue;}
return false;
}
while (*p=='*'){p++;}
return !*p;
}
};
two pointers
771. Jewels and Stones
https://leetcode.com/contest/weekly-contest-69/problems/jewels-and-stones/
You're given strings J representing the types of stones that are jewels, and S representing the stones you have. Each character in S is a type of stone you have. You want to know how many of the stones you have are also jewels. The letters in J are guaranteed distinct, and all characters in J and S are letters. Letters are case sensitive, so "a" is considered a different type of stone from "A". Example : Input: J = "aA", S = "aAAbbbb"
Output:
Example : Input: J = "z", S = "ZZ"
Output:
Note: S and J will consist of letters and have length at most .
The characters in J are distinct.
HashMap。
class Solution {
public:
int numJewelsInStones(string J, string S) {
int res = ;
set<char> s(J.begin(), J.end());
for (char c : S) if (s.find(c) != s.end()) res++;
return res;
}
};
773. Sliding Puzzle
https://leetcode.com/contest/weekly-contest-69/problems/sliding-puzzle/
On a 2x3 board, there are tiles represented by the integers through , and an empty square represented by . A move consists of choosing and a -directionally adjacent number and swapping it. The state of the board is solved if and only if the board is [[,,],[,,]]. Given a puzzle board, return the least number of moves required so that the state of the board is solved. If it is impossible for the state of the board to be solved, return -. Examples: Input: board = [[,,],[,,]]
Output:
Explanation: Swap the and the in one move.
Input: board = [[,,],[,,]]
Output: -
Explanation: No number of moves will make the board solved.
Input: board = [[,,],[,,]]
Output:
Explanation: is the smallest number of moves that solves the board.
An example path:
After move : [[,,],[,,]]
After move : [[,,],[,,]]
After move : [[,,],[,,]]
After move : [[,,],[,,]]
After move : [[,,],[,,]]
After move : [[,,],[,,]]
Input: board = [[,,],[,,]]
Output:
Note: board will be a x array as described above.
board[i][j] will be a permutation of [, , , , , ].
BFS。
class Solution {
public:
int slidingPuzzle(vector<vector<int>>& board) {
queue<vector<vector<int>>> q, next;
set<vector<vector<int>>> s;
vector<vector<int>> res = {{,,}, {,,}};
q.push(board); s.insert(board);
int layer = ;
int bias[] = {, , -, , };
while (!q.empty()) {
while (!q.empty()) {
auto cur = q.front(); q.pop();
if (cur == res) return layer;
pair<int, int> pos = {, };
for (int i = ; i < ; i++) {
for (int j = ; j < ; j++) {
if (cur[i][j] == ) {
pos.first = i;
pos.second = j;
break;
}
}
}
for (int i = ; i < ; i++) {
int x = pos.first + bias[i], y = pos.second + bias[i + ];
if (x >= && x < && y >= && y < ) {
swap(cur[pos.first][pos.second], cur[x][y]);
if (s.find(cur) == s.end()) {
s.insert(cur); next.push(cur);
}
swap(cur[pos.first][pos.second], cur[x][y]);
}
}
}
swap(q, next);
layer++;
}
return -;
}
};
774. Minimize Max Distance to Gas Station
https://leetcode.com/contest/weekly-contest-69/problems/minimize-max-distance-to-gas-station/
On a horizontal number line, we have gas stations at positions stations[], stations[], ..., stations[N-], where N = stations.length. Now, we add K more gas stations so that D, the maximum distance between adjacent gas stations, is minimized. Return the smallest possible value of D. Example: Input: stations = [, , , , , , , , , ], K =
Output: 0.500000
Note: stations.length will be an integer in range [, ].
stations[i] will be an integer in range [, ^].
K will be an integer in range [, ^].
Answers within ^- of the true value will be accepted as correct.
Binary Search。与其他题目不同的是本题需要在整个限制范围内部进行BS,MSRA有一道题和本题相似,都是在整个限制范围内找解,这是一种很重要的思路,DP有时候也会用到这种思想。
class Solution {
public:
double minmaxGasDist(vector<int>& stations, int K) {
double low = , high = 1e8;
for (int rep = ; rep < ; rep++) {
double mid = low + (high - low) / ;
int need = ;
for (int i = ; i < stations.size(); i++) need += (int)((stations[i] - stations[i - ]) / mid);
if (need > K) low = mid;
else high = mid;
}
return high;
}
};
775. Global and Local Inversions
https://leetcode.com/contest/weekly-contest-69/problems/global-and-local-inversions/
We have some permutation A of [, , ..., N - ], where N is the length of A. The number of (global) inversions is the number of i < j with <= i < j < N and A[i] > A[j]. The number of local inversions is the number of i with <= i < N and A[i] > A[i+]. Return true if and only if the number of global inversions is equal to the number of local inversions. Example : Input: A = [,,]
Output: true
Explanation: There is global inversion, and local inversion.
Example : Input: A = [,,]
Output: false
Explanation: There are global inversions, and local inversion.
Note: A will be a permutation of [, , ..., A.length - ].
A will have length in range [, ].
The time limit for this problem has been reduced.
array。
class Solution {
public:
bool isIdealPermutation(vector<int>& A) {
for (int i = ; i < A.size(); i++) {
for (int j = i - ; j >= ; j--) if (A[j] > A[i] && j != i - ) return false;
}
return true;
}
};
796. Rotate String
We are given two strings, A and B. A shift on A consists of taking string A and moving the leftmost character to the rightmost position. For example, if A = 'abcde', then it will be 'bcdea' after one shift on A. Return True if and only if A can become B after some number of shifts on A. Example :
Input: A = 'abcde', B = 'cdeab'
Output: true Example :
Input: A = 'abcde', B = 'abced'
Output: false
Note: A and B will have length at most .
字符串旋转。先判断字母表是否相同,然后逐位旋转一个字符串,看是否与另一个相同,O(N^2)。要旋转字符串s的一部分s[i,j],需要调用reverse(s.begin() + i, s.begin() + j + 1),c++的尾迭代器都是一个字符的下一个,可以参考s.end()迭代器的使用。
class Solution {
public:
bool rotateString(string A, string B) {
vector<int> a_map(), b_map();
for (char c : A) a_map[c]++;
for (char c : B) b_map[c]++;
if (a_map != b_map) return false;
for (int i = ; i < A.size(); i++) {
string tmp(A);
reverse(tmp.begin(), tmp.begin() + i + );
reverse(tmp.begin() + i + , tmp.end());
reverse(tmp.begin(), tmp.end());
if (tmp == B) return true;
}
return false;
}
};
797. All Paths From Source to Target
Given a directed, acyclic graph of N nodes. Find all possible paths from node to node N-, and return them in any order. The graph is given as follows: the nodes are , , ..., graph.length - . graph[i] is a list of all nodes j for which the edge (i, j) exists. Example:
Input: [[,], [], [], []]
Output: [[,,],[,,]]
Explanation: The graph looks like this:
--->
| |
v v
--->
There are two paths: -> -> and -> -> .
Note: The number of nodes in the graph will be in the range [, ].
You can print different paths in any order, but you should keep the order of nodes inside one path.
dfs。从指定起点出发到达指定终点。
class Solution {
public:
vector<vector<int>> allPathsSourceTarget(vector<vector<int>>& graph) {
vector<vector<int>> res;
vector<int> path(, );
vector<bool> visit(graph.size());
visit[] = true;
dfs(graph, , path, visit, res);
return res;
}
void dfs(vector<vector<int>> &graph, int start, vector<int> &path, vector<bool> &visit, vector<vector<int>> &res) {
if ((path.size() > && path.back() + == graph.size())) {
res.push_back(path); return;
} for (int next : graph[start]) {
if (!visit[next]) {
visit[next] = true; path.push_back(next);
dfs(graph, next, path, visit, res);
visit[next] = false; path.pop_back();
} }
}
};
798. Smallest Rotation with Highest Score
Given an array A, we may rotate it by a non-negative integer K so that the array becomes A[K], A[K+1], A{K+2], ... A[A.length - 1], A[0], A[1], ..., A[K-1]. Afterward, any entries that are less than or equal to their index are worth 1 point. For example, if we have [2, 4, 1, 3, 0], and we rotate by K = 2, it becomes [1, 3, 0, 2, 4]. This is worth 3 points because 1 > 0 [no points], 3 > 1 [no points], 0 <= 2 [one point], 2 <= 3 [one point], 4 <= 4 [one point]. Over all possible rotations, return the rotation index K that corresponds to the highest score we could receive. If there are multiple answers, return the smallest such index K. Example 1:
Input: [2, 3, 1, 4, 0]
Output: 3
Explanation:
Scores for each K are listed below:
K = 0, A = [2,3,1,4,0], score 1
K = 1, A = [3,1,4,0,2], score 3
K = 2, A = [1,4,0,2,3], score 3
K = 3, A = [4,0,2,3,1], score 4
K = 4, A = [0,2,3,1,4], score 3
So we should choose K = 3, which has the highest score. Example 2:
Input: [1, 3, 0, 2, 4]
Output: 0
Explanation: A will always have 3 points no matter how it shifts.
So we will choose the smallest K, which is 0.
Note: A will have length at most 20000.
A[i] will be in the range [0, A.length].
DP。一刷使用暴力法O(N^2)超时。大神的DP方法没看懂,继续攻克DP解法。
class Solution {
public:
int bestRotation(vector<int>& A) {
int max_points = , min_k = ;
for (int k = ; k < A.size(); k++) {
int points = ;
for (int i = ; i < A.size(); i++) points += A[(i + k) % A.size()] <= i ? : ;
if (points > max_points) {
max_points = points; min_k = k;
}
}
return min_k;
}
};
brute_force_tle
class Solution {
public int bestRotation(int[] A) {
int[] scoreIncrease = new int[A.length + ];
for (int i = ; i < A.length; i++) {
int v = A[i];
if (i - v >= ) {
scoreIncrease[]++;
scoreIncrease[i - v + ]--;
}
scoreIncrease[i + ]++;
if (i + A.length - v + <= A.length) scoreIncrease[i + A.length - v + ]--;
}
int maxScore = ;
int bestK = ;
int K = -;
int score = ;
while (K < A.length) {
K++;
score += scoreIncrease[K];
if (score > maxScore) {
maxScore = score;
bestK = K;
}
}
return bestK;
}
}
dp
leetcode bugfree note的更多相关文章
-
[LeetCode] Ransom Note 赎金条
Given an arbitrary ransom note string and another string containing letters from all th ...
-
LeetCode: Ransom Note
public class Solution { public boolean canConstruct(String ransomNote, String magazine) { int[] rans ...
-
Leetcode 692 - Note
1. 题目要求 Given a non-empty list of words, return the k most frequent elements. Your answer should be ...
-
LeetCode Crack Note --- 1. Two Sum
Discription Given an array of integers, return indices of the two numbers such that they add up to a ...
-
LeetCode:Ransom Note_383
LeetCode:Ransom Note [问题再现] Given an arbitrary ransom note string and another string contai ...
-
leetcode &; lintcode for bug-free
刷题备忘录,for bug-free leetcode 396. Rotate Function 题意: Given an array of integers A and let n to be it ...
-
LeetCode算法题-Ransom Note(Java实现)
这是悦乐书的第212次更新,第225篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第80题(顺位题号是383).给定一个任意赎金票据字符串和另一个包含所有杂志字母的字符串 ...
-
C#LeetCode刷题之#383-赎金信(Ransom Note)
问题 该文章的最新版本已迁移至个人博客[比特飞],单击链接 https://www.byteflying.com/archives/3937 访问. 给定一个赎金信 (ransom) 字符串和一个杂志 ...
-
【LeetCode】383. Ransom Note 解题报告(Java & Python)
作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 Java解法 Python解法 日期 [LeetCo ...
随机推荐
-
再谈select, iocp, epoll,kqueue及各种I/O复用机制
原文:http://blog.csdn.net/shallwake/article/details/5265287 首先,介绍几种常见的I/O模型及其区别,如下: blocking I/O nonbl ...
-
poj 2239 Selecting Courses(二分匹配简单模板)
http://poj.org/problem?id=2239 这里要处理的是构图问题p (1 <= p <= 7), q (1 <= q <= 12)分别表示第i门课在一周的第 ...
-
NOI2014 动物园
3670: [Noi2014]动物园 Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 174 Solved: 92[Submit][Status] D ...
-
痛并快乐的造*之旅:awk访问数据库之旅
俺是一枚悲催的数据统计程序员,从先辈的手里接收了这样的代码: #! /bin/sh alias statdb="mysql -h 192.168.1.1 -u stat -paaa stat ...
-
Spring+SpringMVC+MyBatis深入学习及搭建(四)——MyBatis输入映射与输出映射
转载请注明出处:http://www.cnblogs.com/Joanna-Yan/p/6878529.html 前面有讲到Spring+SpringMVC+MyBatis深入学习及搭建(三)——My ...
-
Keras官方中文文档:常见问题与解答
所属分类:Keras Keras FAQ:常见问题 如何引用Keras? 如何使Keras调用GPU? 如何在多张GPU卡上使用Keras "batch", "epoch ...
-
Android 友盟SDK 终极解决报错:SocialSDK_QQZone_2.jar contains native libraries that
转自:http://bbs.umeng.com/thread-6552-1-2.html 报错信息:The library `SocialSDK_QQZone_2.jar` contains nati ...
-
jooq实践
用法 sql语句 SELECT AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME, COUNT(*) FROM AUTHOR JOIN BOOK ON AUTHOR.ID = B ...
-
POJ 2431 优先队列
汽车每过一单位消耗一单位油,其中有给定加油站可加油,问到达终点加油的最小次数. 做法很多的题,其中优先对列解这题是很经典的想法,枚举每个加油站,判断下当前油量是否小于0,小于0就在前面挑最大几个直至油 ...
-
PHP json_encode 让URL//不转义
$json_info=json_encode((object)$data,JSON_UNESCAPED_SLASHES);