Leetcode刷题笔记(部分非原创)(1-20题)
1. Two Sum
leetcode链接: https://oj.leetcode.com/problems/two-sum/
最基础的一道题,方法很多,用HashMap存pair是一种(HashSet和HashMap的方法在这里原理是一样的)。也可以sort the whole array first,then use two pointers, one start from the left side, the other from the right side. if array[left]+array[right]>target, move the right index to the left by 1, 小于的话同理. 这里给一个HashMap的方法。
1 public int[] twoSum(int[] numbers, int target) { 2 HashMap<Integer, Integer> map = new HashMap<Integer, Integer>(); 3 int[] result = new int[2]; 4 for(int i = 0; i < numbers.length; i++) { 5 if(map.containsKey(numbers[i])) { 6 int index = map.get(numbers[i]); 7 result[0] = index + 1; 8 result[1] = i + 1; 9 break; 10 } else { 11 map.put(target - numbers[i], i); 12 } 13 } 14 return result; 15 }
2. Median of Two sorted arrays
leetcode链接: https://oj.leetcode.com/problems/median-of-two-sorted-arrays/
首先,比较暴力的方法是统计两个数组的长度(奇数长度有一个median,偶数长度是最中间的两个数的均值),然后两个数组各设置一个index, 谁小,谁的index++,直到两个index走的总长度达到了median所需的长度。这个是O(n)的复杂度。进一步想,数组里找某个数的问题很容易往binary search上面考。这题也不例外。只不过这道题对于边界的控制需要小心,一下写出bug free的代码还是挺有难度的。
关键的是把这个问题转化为第k小的问题。只不过最终找的这个k其实是median。转化为第k小的问题有一个好处,比较好设计成一个recursion的函数。recursion,第一步想清楚base case, 这个recursion里面,第k小的数、这个k是可能会变化的。变化到最后,剩下的某个数组为空,或者k==1的时候,就找到了我们想要的结果,recursion就走到头了。第二步想清楚recursion rule。每次判断剩余的A和B两个数组各自的median,通过比较他们的大小,我们要么舍弃A的前半段和B的后半段,要么舍弃A的后半段和B的前半段。每一个情况又分为两种,如果舍弃的是某个数组的后半段,我们要找的仍然是剩下的元素中间的第k小的数,k不变。如果舍弃的是某个数组的前半段,那么我们的k就要发生变化了,传进下一层recursion的k参数就要发生变化。综上,我们实际上每层recursion会分四种情况讨论。具体的我在下面的代码里做了注释。
1 public double findMedianSortedArrays(int[] A, int[] B) { 2 int lengthA = A.length; 3 int lengthB = B.length; 4 if((lengthA + lengthB) % 2 == 0) { 5 double r1 = (double)findM(A, 0, lengthA, B, 0, lengthB, (lengthA + lengthB) / 2); 6 double r2 = (double)findM(A, 0, lengthA, B, 0, lengthB, (lengthA + lengthB) / 2 + 1); 7 return (r1 + r2) / 2; 8 } else { 9 return findM(A, 0, lengthA, B, 0, lengthB, (lengthA + lengthB) / 2 + 1); 10 } 11 } 12 13 public int findM(int[] A, int startA, int endA, int[] B, int startB, int endB, int k) { 14 //转换为第k小数的问题 15 int n = endA - startA; 16 int m = endB - startB; 17 if(n <= 0) {//corner case & base case of recursion 18 return B[startB + k - 1]; 19 } 20 if(m <= 0) {//corner case & base case of recursion 21 return A[startA + k - 1] 22 } 23 if(k == 1) {//corner case & recursion case of recursion 24 return A[startA] < B[startB] ? A[startA] : B[startB]; 25 } 26 int midA = (startA + endA) / 2; 27 int midB = (startB + endB) / 2; 28 if(A[midA] <= B[midB]) {// the target will appear at the first half of A, or the second half of B 29 if(n / 2 + m / 2 + 1 >= k) {// if in second half of B, k will not change, because we will not cut any number smaller than target 30 return findM(A, startA, endA, B, startB, midB, k); 31 } else {// if in the first half of A, we will cut all the number in the first half, the next step is: find the (k-n/2-1)th smallest number 32 return findM(A, mid + 1, endA, B, startB, endB, k - n / 2 - 1); 33 } else { 34 if(n / 2 + m / 2 + 1 >= k) { 35 return findM(A, startA, midA, B, startB, endB, k); 36 } else { 37 return findM(A, startA, endA, B, midB + 1, endB, k - m / 2 -1); 38 } 39 } 40 }
3. Longest Substring Without Repeating Characters
leetcode链接: https://oj.leetcode.com/problems/longest-substring-without-repeating-characters/
首先能直观的想到暴力的方法,两个指针标记子串的头和尾,hashset来检查是否有重复,两层for循环头和尾,hashset检测到重复以后退出尾部指针的循环,比较与global的大小并更新。但是这里时间复杂度是O(n^2)。一个更好的办法是开辟一个256的数组,作用其实就是个字典表
1 public int lengthOfLongestSubstring(String s) { 2 int[] charMap = new int[256]; 3 Arrays.fill(charMap, -1); 4 int i = 0; 5 int maxLen = 0; 6 for(int j = 0; j < s.length(); j++) { 7 if(charMap[s.charAt(j)] >= i) { 8 i = charMap[s.charAt(j)] + 1; 9 } 10 charMap[s.charAt(j)] = i; 11 maxLen = Math.max(j - i + 1, maxLen); 12 } 13 return maxLen; 14 }
4. Add Two Numbers
leetcode链接: https://oj.leetcode.com/problems/add-two-numbers/
这个题思路很直观,两个链表各一个指针用来读值。另外需要考虑几件事,1. 当某个链表读到头的时候怎么办,2. 这种合并链表的题最好设置dummyHead,3. 最后的最后,如果依然有进位,别把它忘了。其他倒是没啥了。O(m+n)的复杂度
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {int carry = 0;ListNode newHead = new ListNode(0);ListNode p1 = l1;ListNode p2 = l2;ListNode p3 = newHead;while(p1 != null || p2 != null) {if(p1 != null) {carry += p1.val;p1 = p1.next;} if(p2 != null) {carry += p2.val;p2 = p2.next;}p3.next = new ListNode(carry % 10);p3 = p3.next;carry /= 10;} if(carry == 1) {p3.next = new ListNode(1);}return newHead.next; }
5. Longest Palindromic Substring
leetcode链接: https://oj.leetcode.com/problems/longest-palindromic-substring/
这道题思路仍然很直接,循环扫描每个字符,每次从中心开花,找palindrome。但是有几点需要注意:
1. palindrome分为两种,一种是中心有一个元素,然后两边元素满足palindrome,另一种是中心有两个元素,这两个元素相等,然后以他俩为中心两边palindrome
2. corner case:写辅助函数的时候,是否在palindrome为1的时候合法?len2里面,(s, i, i+1),i+1这个参数貌似越界了,真的越界了么,会throw exception么?可以自己把特殊情况带进去,在演草纸上划拉一下,验证下。
3. 审题。题目需要返回的结果是个最长palindrome的substring,而不是int length。所以我们需要在找到更大长度的时候更新start和end这两个index。
public String longestPalindrome(String s) {int start = 0;int end = 0;for(int i = 0; i < s.length(); i++) {int len1 = expandAroundCenter(s, i, i);int len2 = expandAroundCenter(s, i, i + 1);int len = Math.max(len1, len2);if(len > end - start) {start = i - (len - 1) / 2;end = i + len / 2;}}return s.substring(start, end + 1); } public int expandAroundCenter(String s, int left, int right) {int L = left;int R = right;while(L >= 0 && R < s.length() && s.charAt(L) == s.charAt(R)) {L--;R++;} return R - L - 1; }
6. ZigZag Conversion
leetcode链接: https://oj.leetcode.com/problems/zigzag-conversion/
其实是挺没意思的一道题。纯math。在纸上画一个5 row的情况。找到规律即可。注意数组下标的操作不要越界,算清楚。
public String convert(String s, int nRows) {if(s == null || s.length() == 0 || nRows <= 0) {return "";}if(nRows == 1) {return s;}StringBuilder result = new StringBuilder();int size = 2 * nRows - 2;for(int i = 0; i < nRows; i++) {for(int j = i; j < s.length(); j += size) {result.append(s.charAt(j));if(i != 0 && i != nRows - 1) {int temp = j + size - 2 * i;if(temp < s.length()) {result.append(s.charAt(temp));}}}}return result.toString(); }
7. Reverse Integer
leetcode链接: https://oj.leetcode.com/problems/reverse-integer/
最直观的方法是把integer变成charArray,然后把charArray给reverse。需要的额外空间会多一些。下面的方法是直接对数字进行处理。注意会有很多corner case,都是计算机语言对于数字存储的细节方面的知识了。
public int reverse(int x) {if(x == Integer.MIN_VALUE) {return 0;} int num = Math.abs(x);int result = 0;while(num != 0) {if(result > (Integer.MAX_VALUE - num % 10) / 10) {return 0;}result = result * 10 + num % 10;num /= 10;}return x > 0 ? result : -result; }
8. String to Integer(atoi)
leetcode链接:https://oj.leetcode.com/problems/string-to-integer-atoi/
没什么具体的算法思路,考的仍然是对语言细节的掌握和corner case的敏感度。
public static final int maxDivBy10 = Integer.MAX_VALUE / 10;public int atoi(String str) {int i = 0;int n = str.length();while(i < n && Character.isWhitespace(str.charAt(i))) {i++; //regardless of the heading white space } int sigh = 1;if(i < n && str.charAt(i) == '+') {i++;} else if(i < n && str.charAt(i) == '-') {sign = -1;i++;}int num = 0;while(i < n && Character.isDigit(str.charAt(i))) {int digit = Character.getNumericValue(str.charAt(i));if(num > maxDivBy10 || num == maxDivBy10 && digit >= 8) {return sign == 1 ? Integer.MAX_VALUE : Integer.MIN_VALUE;}num = num * 10 + digit;i++;}return sign * num; }
9. Palindrome Number
leetcode链接: https://oj.leetcode.com/problems/palindrome-number/
这个题要求不要有额外的空间。所以转化成字符串比较就行不同了。那就只能每次剥离这个数当前的首尾然后比较。为了取到第一位,我们需要首先生成一个大除数。然后开始循环判断是否palindrome,不要忘了每次大除数要自除100,因为剥离了两个数字。
public boolean isPalindrome(int x) {if(x < 0) {return false; }int div = 1;while(x / div >= 10) {div *= 10;}while(x != 0) {int left = x / div;int right = x % 10;if(left != right) {return false;}x = (x % div) / 10;div /= 100;}return true; }
10. Regular Expression Matching
leetcode链接: https://oj.leetcode.com/problems/regular-expression-matching/
recursion的方法一层一层判断。需要注意的是base case比较多。这也是由于regular expression匹配的情况比较多导致的。
public boolean isMatch(String s, String p) {if(p.length() == 0) {return s.length() == 0;} if(p.length() == 1) {return (s.length() == 1) && (p.charAt(0) == s.charAt(0) || p.charAt(0) == '.');}if(p.charAt(1) != '*') {if(s.length() == 0) {return false;} else {return (s.charAt(0) == p.charAt(0) || p.charAt(0) == '.') && isMatch(s.substring(1), p.substring(1)); }} else {while(s.length() > 0 && (p.charAt(0) == s.charAt(0)) || p.charAt(0) == '.') {if(isMatch(s, p.substring(2))) {return true;}s = s.substring(1);}return isMatch(s, p.substring(2));} }
总结leetcode的前十道题,个人感觉比较好,值得回味的应该是第2,3,4,10题。
11. Container with most water
leetcode链接:https://leetcode.com/problems/container-with-most-water/
这道题需要审题。和trap water是有区别的。trap water是高低不平的一排区间,问能存多少水。而这道题只需要考虑两条边界,中间可以认为是空的,可以存水。实际上难度大大降低。只需要左右两个pointer即可。
1 public int maxArea(int[] height) { 2 if(height.length <= 1) { 3 return 0; 4 } 5 int left = 0; 6 int right = height.length - 1; 7 int max = 0; 8 while(left < right) { 9 max = Math.max(max, (right - left) * Math.min(height[left], height[right])); 10 if(height[left] < height[right]) { 11 left++; 12 } else { 13 right++; 14 } 15 } 16 return max; 17 }
14. Longest common prefix
leetcode链接: https://leetcode.com/problems/longest-common-prefix/
public String longestCommonPrefix(String[] strs) {if(strs == null || strs.length == 0) {return "";}String prefix = strs[0];for(int i = 1; i < strs.length; i++) {int j = 0;for(; j < strs[i].length() && j < prefix.length(); j++) {if(prefix.charAt(j) != strs[i].charAt(j)) {break;}}prefix = prefix.substring(0, j);if(prefix.length() == 0) {break;}}return prefix; }
15. 3 Sum
leetcode链接: https://leetcode.com/problems/3sum/
其实这个3Sum的解法很直接,用3个指针追踪三个数凑出所需的数。唯一需要注意的是这道题需要一个deduplication的过程。
这个deduplication用hashset同样可以解决,不过这个解法更精炼一些。
public List<List<Integer>> threeSum(int[] num) {List<List<Integer>> result = new ArrayList<List<Integer>>();if(num.length < 3 || num == null) {return result;} Arrays.sort(num);for(int i = 0; i < num.length - 2; i++) {if(i == 0 || num[i] > num > num[i - 1]) {int j = i + 1;int k = num.length - 1;while(j < k) {if(num[j] + num[k] == -num[i]) {ArrayList<Integer> list = new ArrayList<Integer>();list.add(num[i]);list.add(num[j]);list.add(num[k]);k--;j++;while(j < k && num[k] == num[k + 1]) {k--;}while(j < k && num[j] == num[j - 1]) {j++;}} else if(num[j] + num[k] > -num[i]) {k--;} else {j++;}}}} }
16. 3Sum Closest
leetcode链接: https://leetcode.com/problems/3sum-closest/
先排序(很重要), 然后循环三个指针, 如果diff出现比min还小, 更新min。
1 public int threeSumClosest(int[] num, int target) { 2 int result = 0; 3 int min = Integer.MAX_VALUE; 4 Arrays.sort(num); 5 for(int i = 0; i < num.length; i++) { 6 int j = i + 1; 7 int k = num.length - 1; 8 while (j < k) { 9 int sum = num[i] + num[j] + num[k]; 10 int diff = Math.abs(target - sum); 11 if(diff == 0) { 12 return sum; 13 } 14 if(diff < min) { 15 min = diff; 16 result = sum; 17 } 18 if(sum <= target) { 19 j++; 20 } else { 21 k--; 22 } 23 } 24 } 25 return result; 26 }
转载于:https://www.cnblogs.com/jianghewade/p/4290007.html
Leetcode刷题笔记(部分非原创)(1-20题)相关推荐
- css总结-笔记--部分非原创--属于资源整合
文章目录 一.css基础教程 1.选择器等级 1.1层叠次序 1.2css三大特性 层叠性原则 继承性 优先级 2.基础语法 2.1声明 2.2值的写法和单位 2.2.1颜色的几种写法(用红色举例) ...
- char java 回文_LeetCode刷题笔记(Java)---第1-18题
题目来自LeetCode 文章目录 全部章节 1-18题 19-40题 41-60题 61-80题 81-100题 101-120题 121-140题 1.两数之和 2.两数相加 3.无重复字符串的最 ...
- 考研数学如何整理错题笔记?140分学长总结的模板,拿走直接用(含错题笔记)
考研数学如何整理错题笔记?140分学长总结的模板,拿走直接用(含错题笔记) 数学错题笔记 2021<考研数学接力题典1800>勘误表(附学霸高分笔记) 2020考研初试成绩已经公布了,对于 ...
- buuctf-MISC篇做题笔记(2)
buuctf-MISC篇做题笔记(2) 第七题:基础破解 先看题目提示,可能也要暴力破解 打开后是RAR文件,需要密码 我是用RARpassword暴力破解,且根据题意已知是四位纯数字密码,设置破解的 ...
- LeetCode部分刷题笔记!!!JavaScript!!!
详细解说请看视频JS老毕:人人都能看得懂的Leetcode力扣刷题教程合集 边看视频边记录笔记!!!部分题目在视频中无! 文章目录 LeetCode第1题:1. 两数之和 LeetCode第2题:2. ...
- LeetCode刷题笔记2——数组2
LeetCode刷题笔记2--数组2 重塑数组 题目 在 MATLAB 中,有一个非常有用的函数 reshape ,它可以将一个 m x n 矩阵重塑为另一个大小不同(r x c)的新矩阵,但保留其原 ...
- LeetCode《算法入门》刷题笔记(31 题全)
LeetCode<算法入门>刷题笔记(31 题全) 二分查找 1. 二分查找 _解法1:二分搜索(迭代) 解法2:二分搜索(递归) 2. 第一个错误的版本 _解法1:二分 3. 搜索插入位 ...
- leetcode分类刷题笔记
leetcode分类刷题笔记--基于python3 写在前面 1.做题如果实在想不出时间复杂度比较优的解法,可以先写出暴力解法,尝试在其基础上优化 2.排序.双指针.二分等--经常可以优化时间复杂度 ...
- LeetCode刷题笔记(算法思想 四)
LeetCode刷题笔记(算法思想 四) 七.动态规划 斐波那契数列 70. 爬楼梯 198. 打家劫舍 213. 打家劫舍 II 信件错排 母牛生产 矩阵路径 64. 最小路径和 62. 不同路径 ...
- 卷进大厂系列之LeetCode刷题笔记:二分查找(简单)
LeetCode刷题笔记:二分查找(简单) 学算法,刷力扣,加油卷,进大厂! 题目描述 涉及算法 题目解答 学算法,刷力扣,加油卷,进大厂! 题目描述 力扣题目链接 给定一个 n 个元素有序的(升序) ...
最新文章
- python拿来干嘛-Python是什么 Python的用处
- 密码协议(三)裁决协议和自动执行协议
- 数据挖掘系列(4)使用weka做关联规则挖掘
- 深度学习:tensorflow的简单用法,tensorflow实现SVM
- 红帽子linux改ip命令,RedHat 7 修改IP地址
- gan神经网络_神经联觉:当艺术遇见GAN
- ES6 学习笔记(一)let,const和解构赋值
- python的编程方式模块化_我的Python笔记·模块化编程(一)
- 【带着canvas去流浪(13)】用Three.js制作简易的MARVEL片头动画(下)
- 2021年软考真题系统分析师真题答案解析汇总
- 虚拟机您的计算机无法启动,一键解决win10虚拟机无法启动的问题
- 百度网盘下载一直请求中问题解决
- nabcd分析解谜类rpg游戏
- 解决:openstack-dashboard-登陆后显示报错
- 聚类——K均值简介及Python实现
- Activities介绍
- SolidWorks Premium 白金版
- 五子棋 手打稍加改变自慕课网hyman
- 无法割舍的乡情--去外公家
- 互联网名称与数字地址分配机构ICANN简介