leetcode题目记录
来源:互联网 发布:cad不能访问到网络锁 编辑:程序博客网 时间:2024/06/06 00:43
leetcode题目
1.TwoSum
a.先排序,再夹逼时间复杂度nlogn 空间复杂度o(n)
b.用hash map,时间和空间复杂度均为O(n)。
2.Add Two Numbers
a.直接顺序相加即可,时间复杂度O(n),用l1 || l2 || carry作为循环的判断条件,carry代表进位。
3.Longest Substring Without Repeating Characters
a.使用unordered_map保存字符及它们的位置。O(n)。算法中保存三个遍历,目前合法字符串的起始点,目前合法字符串的长度,以及要求的结果。
4.Median of Two Sorted Arrays
a.经典题目,二分法的经典题目。注意边界条件,k=1,m=0或者A[pa-1]==B[pb-1]。递归式子为return findKth(a + pa, m - pa, b, n, k - pa),以及return findKth(a, m, b + pb, n - pb, k - pb);
5.Longest Palindromic Substring
a.经典二维DP。
6.ZigZag Conversion
a.注意numRows为1时,直接返回原来的string。
7.Reverse Integer
a.unsigned long long,注意上溢和下溢。另外,比较不同类型时,需要进行强制转换。低阶转高阶。
8.String to Integer (atoi)
流程:
left++; right--; while(num[left]==num[left-1]) left++; while(num[right]==num[right+1]) right--;
16.3Sum Closest
a.双指针扫描,注意解法中维护的变量是误差,在这里,误差可正可负。
int diff = num[i]+num[left]+num[right]-target;if(abs(diff)<abs(minDiff)) minDiff = diff;
17.Letter Combinations of a Phone Number
a.一开始想的使用回溯法,但是会用到一个hash map,key保存数字,value为对应的字符串。后来看到更方便的定义形式。string dict[] = {" ","","abc","def","ghi","jkl","mno","pqrs","tuv","wxyz"};
b.注意,此题的非递归做法!!!也就是插入法。要充分理解插入法的逻辑。注意在结果中要先插入空字符串,如下:
vector<string> lettComb;lettComb.push_back("");18.4Sum
a.用传统方法,四个指针方法。i != 0 && nums[i] == nums[i-1], j != i+1 && nums[j] == nums[j-1]。
b.用hash_map方法。map的key为两个元素的和,value为两个元素的坐标。通过下列语句去重。if(isFirstPush || (res.back())[2] != num[sum2[k].first])。
19.Remove Nth Node From End of List
a.快慢指针,快指针先走n步,慢指针再走。
20.Valid Parentheses
a.经典的进栈和出栈问题。
21.Merge Two Sorted Lists
a.需要注意的一点是,当一个list为空时,结果链表指针link可以直接->next=list。
22.Generate Parentheses
a.只要(的数目小于n,就可以插入(。而可以插入)的前提是当前(的数目多余)的数目。
23.Merge k Sorted Lists
a.用优先级队列(最小堆),时间复杂度为O(nklogk),空间复杂度为O(k),priority_queue,要会写cmp函数,以及如何声明priority_queue
b.循环两两合并。时间复杂度为O(n*k^2)。
c.二分合并,时间复杂度为O(nklogk),空间复杂度为O(1),二分非递归合并用到了两个while循环,和begin和end循环变量,非常精巧。
24.Swap Nodes in Pairs
a.使用三个指针,扫描完成。
25.Reverse Nodes in k-Group
a.题目要求只用常量空间。所以在这里不能用数组栈。最好的方法是把一段段链表看成goup,翻转group里面的节点。
26.Remove Duplicates from Sorted Array
a.双指针,一个扫描数组,一个用来记录不重复数字序列的后面那一位。nums[left++] =nums[i++]。
27.Remove Element
a.同样是双指针解法。nums[left++]=nums[i++];
29.Divide Two Integers
a.计算左移多少次可以使pDivisor<<numShift刚刚大于pDividend,另外需要注意一些边界条件。
while (lDividend>=lDivisor) {
int shift_num = 0;
while (lDividend>=(lDivisor<<shift_num)) {
shift_num++;
}
ret += (1<<(shift_num-1));
lDividend -=(lDivisor<<(shift_num-1));
}
30.Substring with Concatenation of All Words
a.滑动窗口解法。把每个单词当成一个字符那样对待。
for(int i = 0; i < wordLen; i++)
{//为了不遗漏从s的每一个位置开始的子串,第一层循环为单词的长度
unordered_map<string, int>wordTimes2;//当前窗口中单词出现的次数
int winStart = i, cnt = 0;//winStart为窗口起始位置,cnt为当前窗口中的单词数目
for(int winEnd = i; winEnd <= (int)S.size()-wordLen; winEnd+=wordLen)
31.Next Permutation
a.从右至左,找一个a[i]<a[i+1]的数.从右至左找到第一个比a[i]大的元素。交换这两个元素。翻转[i+1, n-1]。记牢。
32.Longest Valid Parentheses
a.DP做法。dp[i]代表以s[i-1]为结尾的longest valid parentheses substring的长度。时间复杂度为O(n)。递推公式为:
s[i-1] = '(':
DP[i] = 0
s[i-1] = ')':找i前一个字符的最长括号串DP[i-1]的前一个字符j = i-2-DP[i-1]
DP[i] = DP[i-1] + 2 + DP[j],如果j >=0,且s[j] = '('
DP[i] = 0,如果j<0,或s[j] = ')'
且DP[0] = 0
b.stack做法,stack保存下标。
33.Search in Rotated Sorted Array I
a.原数组0 1 2 3 4 5 6,然后旋转2 3 4 5 6 0 1和5 6 0 1 2 3 4,找规律。要求数字正好是7个。向右旋转2个或者5个。通过比较nums[mid]和nums[end]发现有序的那半边。
34.Search for a Range
a.需要分别查找左边界和右边界。
if(start>=0 && start<n && A[start]==target) return start;35.Valid Sudoku
a.关键在于去重。需要注意三点:1.后面选择数的index一定>=前面选择的数的index。2.不考虑跟上一个数字重复的数字。
例1:
for(int i = index; i < candidates.size() && target >= candidates[i]; i++)
例2:
if(i == 0 || candidates[i] != candidates[i-1])
40.Combination Sum II
a.在for循环中,也就是某layer尝试放入下一个数y的时候,我们提前判断下一个数y是否跟当前的数x相等,如果相等,我们就直接跳过去,因为第一次放x的时候,实际上已经包含了conbination包含x的所有可能性,再尝试y就会产生重复。
for(int i=start; i<num.size(); i++) { if(i>start && num[i]==num[i-1]) continue;
41.First Missing Positive
a.如果一道题用O(n)时间,常量空间,那么要向桶排序和计数排序进行思考,这道题用输入数组用来做桶排序的空间。注意条件A[i]!=A[A[i]-1]是为了避免死循环,比如[1,1]。
while(i<n) { if(A[i]!=i+1 && A[i]>0 && A[i]<=n && A[i]!=A[A[i]-1]) swap(A[i],A[A[i]-1]); else i++; }
42.Trapping Rain Watera.对任意位置i,在i上的积水,由左右两边最高的bar:A[left] = max{A[j], j<i}, A[right] = max{A[j], j>i}决定。定义Hmin = min(A[left], A[right]),则积水量Si为:
Hmin <= A[i]时,Si = 0
Hmin > A[i]时,Si = Hmin - A[i]
43.Multiply Strings
a.把两个single digit相乘得到的结果可以保存到一个数组中。注意m位*n位,结果最大为m+n位。
44.Wildcard Matching
a.贪心和回溯,双指针i和j分别在s和p上游动。保存*的位置,以及遇到*时,s的位置。
45.Jump Game II
a.d[k] = max(i+A[i]) d[k-2] < i <= d[k-1].贪心算法。
class Solution {public: int jump(int A[], int n) { int curMax = 0, njumps = 0, i = 0; while(curMax<n-1) { int lastMax = curMax; for(; i<=lastMax; i++) curMax = max(curMax,i+A[i]); njumps++; if(lastMax == curMax) return -1; } return njumps; }};46.Permutations
a.插入法即可。但是要注意一些细节。比如:
allPer.push_back(vector<int>(1,num[0]));
allPer[j].push_back(num[i]);
47.Permutations II
a.情况与combination II差不多。
if(used[i]) continue;if(i>0 && num[i]==num[i-1] && !used[i-1]) continue;
48.Rotate Image
a.从外到内,对每层进行翻转。
49.Group Anagrams
关键点:如果两个字符串互为anagram,则它们的排序结果一定相同。
50.Pow(x, n)
a.分治递归。
54.Spiral Matrix
a.本题为打印螺旋矩阵。我们逐个环进行打印,对于m*n的矩阵,环的个数为(min(m, n)+1)/2。对于每个环,顺时针打印四条边。需要注意的一点是,最后一个环可能只含有一行或者一列数据。
利用环的思想,并利用环当前的高度和宽度。
56.Merge Intervals
a.首先按照start的大小来给所有interval排序,start小的在前。然后扫描逐个插入结果。如果发现当前interval a和结果中最后一个插入的interval b不重合,则插入a到b的后面;反之如果重合,则将a合并到b中。注意要给object排序需要定义一个compare structure作为sort函数的额外参数。
太精彩的算法!!!
57.Insert Interval
a.遍历数组,如果当前interval在newInterval前面,则将当前interval插入结果中;如果当前interval在newInterval后面,则将newInterval插入结果并把newInterval赋值为当前interval;如果两者重叠,则合并两个区间,修改newInterval的数值,这三种情形如下图所示。图中的Current对应newInterval,New对应intervals[i]。
59.Spiral Matrix II
a.我们也是逐个环地进行填充,每个环顺时针逐条边填充。每个环的左上角起点是matrix[i][i],之后顺时针依次填充环的四条边 。
62.Unique Paths
a.数学组合公式或者一维动态规划。
64.Minimum Path Sum
a.动态规划。一维。滚动数组。
65.Valid Number
有限状态自动机,厘清所有状态,以及状态转换。
69.Sqrt(x)
a.牛顿迭代法。
72.Edit Distance
a.dp[i][j] = min(dp[i-1][j-1], min(dp[i-1][j], dp[i][j-1])) + 1;
73.Set Matrix Zeroe
a.用矩阵的第一行和第一列来记录。
75.Sort Colors
a.这道题目的思想很像快速排序,把0往左边放,把2往右边放。用三个指针进行操作,分别为i,left, right。代码如下:
int left=0, right=n-1;int i = 0;while(i<=right) {if(A[i]==0)
swap(A[i++],A[left++]); else if(A[i]==1) i++; else if(A[i]==2) swap(A[i],A[right--]);}
76.Minimum Window Substring
a.1.先搜索到满足条件的窗口,然后再试着是否能够从左向右缩小窗口(当前字符不在t中,或者去掉当前字符,剩下的字符仍然是窗口)。2.start = start+1(此时窗口肯定不会包含所有的T中的字符),跳转到步骤1继续寻找下一个窗口.3.用哈希表来映射T中字符以便在O(1)时间内判断一个字符是否在T中,由于是字符缘故,可以用数组简单地来实现;还需要一个哈希表来记录扫描时T中的某个字符在S中出现的次数,也可以用数组实现。
81.Search in Rotated Sorted Array II
a.A[mid] = A[end] != target时:搜寻A[start : end-1]
82.Remove Duplicates from Sorted List II
a.II比I难在需要删除所有的重复节点。这里需要注意两点:1. 头节点也可能被删除。可以使用dummy节点来简化。2. 如果采用与I类似的思路来删除当前节点后所有的重复节点,则完成后还需要把当前节点也删除。因此需要有一个变量来记录当前节点是否有重复。
83.Remove Duplicates from Sorted List I
a.由于list已经排序过,重复节点必相邻。由于链表指针是单向的,所以访问每个节点时,判断后一个节点是否是重复节点,如果是,则删除后一个节点。由于I中重复节点要保留一个,如果碰到重复删除后节点,则不需要考虑删除头指针的特殊情况。
84.Largest Rectangle in Histogram
a.仔细考察Brute Force算法,发现问题在于指针重复扫描。以递增序列为例:
0 1 2 3 4 5 6
在计算s[0]的时候扫描了右边6个数,计算s[1]时继续扫描右边5个数,依次类推。而没能利用到这个序列的递增性质。当序列从i递增到j时,bar i~j的面积一定都能扩展到j。而一旦在j+1递减了,那么表示bar i~j中的部分bar k无法继续扩展,条件是h[k]>h[j+1]。
1. 利用这个性质,可以将递增序列cache在一个stack中,一旦遇到递减,则根据h[j+1]来依次从stack里pop出那些无法继续扩展的bar k,并计算面积。
2. 由于面积的计算需要同时知道高度和宽度,所以在stack中存储的是序列的坐标而不是高度。因为知道坐标后很容易就能知道高度,而反之则不行。
85.Maximal Rectangle
a.回想leetcode的另一题计算直方图最大面积:Largest Rectangle in Histogram,它可以在O(n)时间内解决,这一题可以转化成求直方图最大面积问题,对每一行中的每个位置,计算该位置所在列向上的1的连续个数,这样每一行中每个位置1的个数就形成了一个直方图,对每一行调用计算直方图面积的算法,就可以求出最大的面积。下面代码中height就是保存每一行每个位置1的个数,并且和上面解法中求dp类似,每一行的height可以由上一行的height求得。
87.Scramble String
a.动态规划用数组来保存子问题,设dp[k][i][j]表示s2从j开始长度为k的子串是否可以由s1从i开始长度为k的子串转换而成,那么动态规划方程如下
- 初始条件:dp[1][i][j] = (s1[i] == s2[j] ? true : false)
- dp[k][i][j] = ( dp[divlen][i][j] && dp[k-divlen][i+divlen][j+divlen] ) || ( dp[divlen][i][j+k-divlen] && dp[k-divlen][i+divlen][j] ) (divlen = 1,2,3...k-1, 它表示子串分割点到子串起始端的距离) ,只要一个子问题返回真,就可以停止计算
88.Merge Sorted Array
a.The key to solve this problem is moving element of A and B backwards. If B has some elements leftafter A is done, also need to handle that case.。
89.Gray Code
a.二进制转grey码的公式。gray = (binary) xor (binary >> 1).
95.Unique Binary Search Trees II
a.1. 根节点可以任取min ~ max (例如min = 1, max = n),假如取定为i。
- dp[i][j] = (dp[i][j-1] ==true && s3[i+j-1] == s2[j-1]) || (dp[i-1][j] == true && s3[i-1+j] == s1[i-1])
- 初始条件:if(s1[0] == s3[0])dp[1][0] = true , if(s2[0] == s3[0])dp[0][1] = true; 其他值均为false
class Solution {public: bool isSameTree(TreeNode *p, TreeNode *q) { if(!p && !q) return true; if((!p && q) || (p && !q)) return false; if(p->val != q->val) return false; return isSameTree(p->left,q->left) && isSameTree(p->right,q->right); }};
101.Symmetric Tree
a.迭代解法本质上和递归解法是一回事,尽管理解上没有递归这么直观简洁。通常用stack或queue来暂时存放之后要处理的节点。这里由于要判断左右子树是否镜像,用两个queue分别对左右子树进行BFS的一层一层地访问。在访问中压入子节点到两个queue时,采用完全相反的顺序:对左子树先压入left child再right child;对右子树先压入right child再left child。这样一来将symmetric tree问题又转换为了same tree问题。
105.Construct Binary Tree from Preorder and Inorder Traversal
a.root->left = helper(pBegin+1, pBegin+1+(rootIter-iBegin), iBegin, rootIter);
root->right = helper(pBegin+1+(rootIter-iBegin), pEnd, rootIter+1, iEnd);
108.Convert Sorted Array to Binary Search Tree
a.找到数组的中间数据作为根节点,小于中间数据的数组来构造作为左子树,大于中间数据的数组来构造右子树,递归解法如下。
109.Convert Sorted List to Binary Search Tree
TreeNode* helper(ListNode* start, ListNode* end) {
if (start==end) {
return NULL;
}
ListNode* fast = start, *slow = start;
while (fast->next!=end&&fast->next->next!=end) {
slow = slow->next;
fast = fast->next->next;
}
TreeNode* parent = new TreeNode(slow->val);
parent->left = helper(start, slow);
parent->right = helper(slow->next, end);
return parent;
}
110.Balanced Binary Tree
a.用height是否为-1标记树是否是平衡的。
class Solution {public: bool isBalanced(TreeNode *root) { return findDepth(root)==-1 ? false : true; } int findDepth(TreeNode *root) { if(!root) return 0; int leftDepth = findDepth(root->left); // left subtree depth if(leftDepth==-1) return -1; int rightDepth = findDepth(root->right); // right subtree depth if(rightDepth==-1) return -1; if(abs(leftDepth-rightDepth)>1) return -1; return max(leftDepth,rightDepth)+1; }};
115.Distinct Subsequences
a.动态规划,设dp[i][j]是从字符串S[0...i]中删除几个字符得到字符串T[0...j]的不同的删除方法种类,有上面递归的分析可知,动态规划方程如下
- 如果S[i] = T[j], dp[i][j] = dp[i-1][j-1]+dp[i-1][j]
- 如果S[i] 不等于 T[j], dp[i][j] = dp[i-1][j]
- 初始条件:当T为空字符串时,从任意的S删除几个字符得到T的方法为1。
116和117题
递推:在第i层的所有next pointer都连接好的情况下,如何连接第i+1层的next pointer?
显然从第i层的最左节点开始依次通过next pointer遍历这一层,同时将他们的children,即第i+1层的节点依次通过next pointer连接起来。连接的时候要分情况处理。
初始情况:对于顶层,只有一个节点root,所以该层连接已经完成。
保存first指针和last指针,分别为下一层第一个与下一层最后遍历的元素,还要注意指针是怎样移动的。
这道题的关键之处,就在于想清楚最后两层。!!!
121
维持一个当前最小值,这样的trick需要牢记。
122
资本家心态,不放过一丝一毫可以挣钱的机会!!!!
123
124
ret作为引用参与递归,递归函数的返回值为root或者root加左子树或者root+右子树
126题
注意点1:在求最短搜索路径,树最小深度的问题,使用bfs,实际上树的层序遍历便是bfs。
注意点2:找到一个相邻单词时候,加入bfs队列后,要从字典中删除。不删除会造成死循环。
127题
如何保证求得所有最短路径?
1.当前层遍历完后,再把所有相邻词从dict删除。
2.用hashtable控制不把重复元素放进队列。
如何构造路径?
使用一个hash表,key为单词,value为前驱单词列表。最后递归反向得到路径。
130
bfs中的注意事项!!!bfs!!!!
133.
bfs队列,dfs用stack!!!
只考虑第一层的所有情形,想得过深会让脑细胞不够用!!
134
挺trick的一道题目,需要反证法思想。
135经典双向扫描。
137
- 显现a的左起第i+1位: a & 1 << i
- 把a的左起第i+1位置零:a &= ~(1 << i)
- 把a的左起第i+1位置1:result |= 1 << i
139
只是求能否break,并且起点和终点都是固定的,所以从二维DP换到一维DP。
140
得到二维数组用于存放前驱路径
141
双指针追赶法
142
推理过程一定要熟记于心。!!!
143
1.找到后半段(起点为L/2+1个节点,L为链表节点数),
2.翻转后半段(翻转后,把后半段第一个节点的next设置为NULL)
3.后半段插入前半段(用right->next是否为NULL控制是否停止)
重要的一个trick是:在翻转后半段的时候,把第L/2+1个节点的next设置为NULL。
145
后续遍历输出的情况只有一种,p的前驱prev的right为p时,这个时候,倒序输出p->left到prev。注意先print,之后再把prev->right=NULL。
146.
用unordered_map和list
147
喜刷刷的解法更简便。
149
- 当对每个点,看有多少其他点跟它在一条直线上时候,只看在它后面的点,这样是为了避免重复计算。
- 用hash map来保存在某个斜率下,有多少点跟当前点在同一条直线上。在这里斜率是关键!!!!!!
151.注意保存large之前的数值。要谨慎,仔细!!
155.用两个stack,其中一个stack保存目前为止的最小值。
160.如果两个链表相交,则它们的尾巴节点必然相同
162.1.注意找到任何一个peak数就行
2.任意两个相邻的数均不相等。
3.通过nums[mid]和nums[mid+1]进行比较来缩减一半的范围。
164
1.len=(large-small)/n+1
buck_num = (large-small)/len+1
哪个桶(num-small)/len
很有意思的一道题目!精彩!!
- leetcode题目记录
- leetcode 题目记录:7,8
- leetcode 刷题目,总结,记录,备忘 13
- leetcode刷题目 ,总结,记录,备忘206
- leetcode刷题目 总结 记录 备忘11
- LeetCode OJ 上 Database 题目记录集
- leetcode经典题目及解法记录
- 【LeetCode题目记录-4】插入数组间隔问题
- 【LeetCode题目记录-5】二叉树是否相同
- 【LeetCode题目记录-12】所有合法的括号序列
- Leetcode 题目记录:231,342,191, 190,172,258,292
- 题目记录
- 题目记录
- 题目记录
- leetcode题目
- LeetCode 题目
- < 题目 > LeetCode
- 【LeetCode题目记录-2】从前序遍历和中序遍历构建二叉树
- 大型数据库的分析技巧-统计学基础
- 什么是Polymer?
- Longest Palindromic Substring O(N) solution
- HTTP协议超级详解
- activity大总结
- leetcode题目记录
- *LeetCode-Paint House
- 给那些认为Grunt奇怪又难懂的人看的Grunt教程
- LeetCode OJ 11 Container With Most Water
- 给那些认为Grunt奇怪又难懂的人看的Grunt教程(二)
- Grunt即学即用
- LeetCode OJ 12 Integer to Roman
- iOS超全学习资料
- Servlet学习笔记二(会话技术)