LeetCode面试常见100题( TOP 100 Liked Questions)
这篇文章是关于LeetCode Top 100 Liked Questions 的 专栏记录,其中部分题目可能包括解题思路和多种优化解法。我把自己的思路都记录在这里,如果你看见了,请记得点个赞吧,蟹蟹【手动笑脸】。
目录:
-
- 1、Two Sum
- 2、Add Two Numbers
- 3、Longest Substring Without Repeating Characters
- 4. Median of Two Sorted Arrays
- 5、Longest Palindromic Substring
- 11. Container With Most Water
- 15. 3Sum
- 16. 3Sum Closest
- 17. Letter Combinations of a Phone Number
- 19. Remove Nth Node From End of List
- 20. Valid Parentheses
- 21. Merge Two Sorted Lists
- 22. Generate Parentheses
- 23. Merge k Sorted Lists
- 32. Longest Valid Parentheses
- 33. Search in Rotated Sorted Array
- 34. Find First and Last Position of Element in Sorted Array
- 35. Search Insert Position
- 39. Combination Sum
- 42. Trapping Rain Water
- 46. Permutations
- 48. Rotate Image
- 49. Group Anagrams
- 53. Maximum Subarray
- 55. Jump Game
- 56. Merge Intervals
1、Two Sum
Given an array of integers, return indices of the two numbers such that they add up to a specific target.
You may assume that each input would have exactly one solution, and you may not use the same element twice.
Example:
Given nums = [2, 7, 11, 15], target = 9, Because nums[0] + nums[1] = 2 + 7 = 9, return [0, 1].
- 1
- 2
- 3
- 4
/**
* Given an array of integers, return indices of the two numbers such that they add up to a specific target.
* You may assume that each input would have exactly one solution, and you may not use the same element twice.
* Example:
* Given nums = [2, 7, 11, 15], target = 9,
* Because nums[0] + nums[1] = 2 + 7 = 9,
* return [0, 1].
* @param nums
* @param target
* @return
*/
public static int[] twoSum(int[] nums, int target) { int[] result= new int[2]; if(nums.length>1){ for(int i=0;i<nums.length;i++){ for(int j=i+1;j<nums.length;j++){ if(nums[i]+nums[j]==target){ result[0]=i; result[1]=j; } } } } return result; }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
2、Add Two Numbers
Description:
You are given two non-empty linked lists representing two non-negative integers. The digits are stored in reverse order and each of their nodes contain a single digit. Add the two numbers and return it as a linked list.
You may assume the two numbers do not contain any leading zero, except the number 0 itself.
Example:
Input: (2 -> 4 -> 3) + (5 -> 6 -> 4) Output: 7 -> 0 -> 8 Explanation: 342 + 465 = 807.
- 1
- 2
- 3
/**
* Description:You are given two non-empty linked lists representing two non-negative integers.
* The digits are stored in reverse order and each of their nodes contain a single digit.
* Add the two numbers and return it as a linked list.
* You may assume the two numbers do not contain any leading zero, except the number 0 itself.
* Example:
* Input: (2 -> 4 -> 3) + (5 -> 6 -> 4)
* Output: 7 -> 0 -> 8
* Explanation: 342 + 465 = 807.
* @param l1
* @param l2
* @return
*/
public static ListNode addTwoNumbers(ListNode l1, ListNode l2) {
ListNode result = new ListNode(0); //创建头结点 ListNode phead = result; int flag =0; //进位 while(l1!=null && l2!=null ){//连个链表都不为空 int val = l1.val + l2.val + flag; flag = 0; if(val>9){ flag =1; val = val % 10; } //创建链表节点并添加到head尾 ListNode temp = new ListNode(val); phead.next=temp; l1 = l1.next; l2 = l2.next; phead = phead.next; } if(l1 == null){//如果l1已经遍历完成,而l2还不为空 while(l2!=null){ int val = l2.val + flag; flag =0; if(val >9){ flag =1; val = val % 10; } ListNode temp = new ListNode(val); phead.next = temp; l2 = l2.next; phead = phead.next; } } if(l2 == null){ while(l1 !=null){ int val = l1.val + flag; flag =0; if(val >9){ flag =1; val = val % 10; } ListNode temp = new ListNode(val); phead.next = temp; l1 = l1.next; phead = phead.next; } } if(flag ==1){ ListNode temp = new ListNode(1); phead.next = temp; } return result.next; }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
优化解法:
/**
* 解法二:
* @param l1
* @param l2
* @return
*/
public ListNode addTwoNumbers2(ListNode l1, ListNode l2) { ListNode dummyHead = new ListNode(0); ListNode p = l1, q = l2, curr = dummyHead; int carry = 0; while (p != null || q != null) { int x = (p != null) ? p.val : 0; int y = (q != null) ? q.val : 0; int sum = carry + x + y; carry = sum / 10; curr.next = new ListNode(sum % 10); curr = curr.next; if (p != null) p = p.next; if (q != null) q = q.next; } if (carry > 0) { curr.next = new ListNode(carry); } return dummyHead.next; }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
3、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 3.
Given "bbbbb", the answer is "b", with the length of 1. Given "pwwkew", the answer is "wke", with the length of 3.
- 1
- 2
- 3
- 4
- 5
- 6
Note that the answer must be a substring, “pwke” is a subsequence and not a substring.
/**
* 题目描述:
* Given a string, find the length of the longest substring without repeating
* characters.
* Examples:
* Given "abcabcbb", the answer is "abc", which the length is 3. * Given "bbbbb", the answer is "b", with the length of 1. * Given "pwwkew", the answer is "wke", with the length of 3. Note that the * answer * must be a substring, "pwke" is a subsequence and not a substring. * 解题思路: * 利用滑动窗口[i,j)表示从位置i到j的子字符串str,用集合Set表示str中的字符集合,用maxL表示该字符串 * 长度,进行以下操作: * 1)先滑动窗口的右部边界,即j+1,判断str中是否出现重复字符: * 若果未出现,则更新Set和maxL,并继续1)步骤 * 如果出现重复步骤,则表示当前子串已不能再扩大长度,故执行2)步骤 * 2)滑动窗口的左部边界,接i+1,同时判断str中是否包含重复字符 * @param s */ public int lengthOfLongestSubstring(String s) { int maxL = 0; //记录最大子串的长度 Set<Character> charSet = new HashSet<Character>(); int i=0,j=0; //滑动窗口的起点和终点 while(i<s.length() && j<s.length()){ if(!charSet.contains(s.charAt(j))){ charSet.add(s.charAt(j)); maxL = Math.max(maxL,j-i+1); j++; }else{ charSet.remove(s.charAt(i)); i++; } } return maxL; }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
/**
* 优化解法:
* 思路:
* 实际上根据以上思路我们可以得出更加优化的解法:
* 我们可以用hashmap存储字符串的字符与索引之间的对应关系,这样当滑动窗口检[i,j)测出重复字符时:
* 我们只需要找到该字符在hashmap中的索引,假定为j',那么我们只需要将i置为j'+1,并重新开始找就可以了
* @param args
*/
public static int lengthOfLongestSubstring2(String s) { int maxL = 0; //记录最大子串的长度 Map<Character,Integer> hashmap = new HashMap<Character,Integer>(); int i=0,j=0; //滑动窗口的起点和终点 while(i<s.length() && j<s.length()){ if(!hashmap.containsKey(s.charAt(j))){ hashmap.put(s.charAt(j), j); maxL = Math.max(maxL,j-i+1); j++; }else{ int index = hashmap.get(s.charAt(j)); //获取重复字符的索引 for(int k=i;k<=index;k++){ hashmap.remove(s.charAt(k)); } i = index +1; } } return maxL; }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
4. Median of Two Sorted Arrays
Description:
There are two sorted arrays nums1 and nums2 of size m and n respectively.
Find the median of the two sorted arrays. The overall run time complexity should be O(log (m+n)).
You may assume nums1 and nums2 cannot be both empty.
Example 1:
nums1 = [1, 3]
nums2 = [2]
The median is 2.0
- 1
- 2
- 3
Example 2:
nums1 = [1, 2]
nums2 = [3, 4]
The median is (2 + 3)/2 = 2.5
- 1
- 2
- 3
/**
* 4. Median of Two Sorted Arrays
* Description:
* There are two sorted arrays nums1 and nums2 of size m and n respectively.
* Find the median of the two sorted arrays. The overall run time complexity should be O(log (m+n)).
* Example 1:
* nums1 = [1, 3]
* nums2 = [2]
* The median is 2.0
* Example 2:
* nums1 = [1, 2]
* nums2 = [3, 4]
* The median is (2 + 3)/2 = 2.5
*************************************************************************
* 思路:
* 我们将两个有序数组分别用A[:m-1]、B[:n-1]来表示。
* 假定我们用A[:i-1]、A[i:m-1]将数组A切分;用B[:j-1]、B[j:n-1]将数组B切分;则只要保证以下条件:
* 1)i+j = m-i + n-j;(此时,i=0~m,j=(m+n+1)/2 -i);注意为了保证j非负,这里n>=m
* 2)B[j-1] <= A[i],A[i-1] <= B[j]
* 那么我们就可以计算出:
* median = (max(left_part) + min(right_part))/2
* 综合以上思路,解题的关键就是寻找合适的i和j,这里我们拟采用“二分查找法”。步骤如下
* 假定 imin=0,imax=m;则我们需要在[imin,imax]中寻找合适的i值,我们假设:
* i = (imin + imax)/2, j=(m+n+1)/2 - i,这样我们可以保证len(left_part) = len(right_part)
* 在以上假定之后,我们共有以下三种情况需要考虑:
* 1) B[j-1]<= A[i] 且 A[i-1] <= B[j]: 此时 i刚好满足情况
* 2) B[j-1] > A[i]: 此时说明i值太小,需要增加i,这时我们需要置 imin = i+1
* 3) A[i-1] > B[j]: 此时寿命i值过大,需要减小i,这时我们需要置 imax = i-1
* 最终结果为:
* 1)如果 m+n 为奇数,则 median = max(A[i-1],B[j-1])
* 2)如果 m+n 为偶数,则 median = (max(A[i-1],B[j-1]) + min(A[i],B[j]))/2
*
*************************************************************************
* @param args
*/
public static double findMedianSortedArrays(int[] A, int[] B) { int m = A.length; int n = B.length; //判断第一个条件,m<=n if(m > n){ int[] temp = A; A = B; B = temp; m = A.length; n = B.length; } int imin =0, imax = m; int i=0,j=0; int maxleft =0, minright=0; if(m==0 && n==0){ return 0; }else if(m==0 && n==1){ // 当其中一个为空数组,另一个长度为1 return B[0]; }else{ while(imin <= imax){ i = (imin+imax)/2; j = (m+n+1)/2 -i; if(i < m && B[j-1] > A[i]) imin = i +1; else if(i > 0 && A[i-1] > B[j]) imax = i -1; else{ //符合条件 if(i==0) maxleft = B[j-1]; else if (j==0) maxleft = A[i-1]; else maxleft = Math.max(A[i-1], B[j-1]); if(i==m) minright = B[j]; else if(j==n) minright = A[i]; else minright = Math.min(B[j], A[i]); break; } } } if( (m+n)%2 ==0){//为偶数 return (maxleft + minright)/2.0; }else return maxleft; }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
5、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 1000.
Example 1:
Input: "babad"
Output: "bab"
- 1
- 2
Note: “aba” is also a valid answer.
Example 2:
Input: "cbbd"
Output: "bb"
- 1
- 2
/**
* 5、Longest Palindromic Substring 回文结构
* Given a string s, find the longest palindromic substring in s. You may assume that the maximum length of s is 1000.
* Example 1:
* Input: "babad"
* Output: "bab"
* Note: "aba" is also a valid answer.
* Example 2:
* Input: "cbbd"
* Output: "bb"
*/
/**解法一:暴力解法
* @param s
* @return
*/
public static String longestPalindrome(String s) { int maxLength=0; String LongestStr=""; int length = s.length(); for(int i=0;i<length;i++){ for(int j=length-1;j>=i;j--) if(isPalindrome(i,j,s)){ int subLen = j-i+1; if(subLen>maxLength){ LongestStr = s.substring(i,j+1); maxLength=subLen; } } } return LongestStr; } /** * 判断字符串是否为回文结构 * @param startIndex * @param endIndex * @param s * @return */ public static boolean isPalindrome(int startIndex,int endIndex,String s){ int i=startIndex,j=endIndex; for(;j>=i;i++,j--){ if(s.charAt(i)!=s.charAt(j)) return false; } return true; }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
/**
* 5、 Longest Palindromic Substring
* 优化解法二:动态规划解法
* 思路:
* 利用dp[j][i]表示字符串区间[j,i]是否为回文串,则dp[i][j]
* 即如果我们找到两个相同的字符S[i]和S[j],在两种情况下他们能构成回文串:
* 第一种:这两个字符位置相邻或者就是同一个字符 即:
* dp[j][i] = (S[i]==S[j]) && (i-j<2)
* 第二种:这两个字符所包含的中间字符串为回文串,这个时候我们只需要验证:
* dp[j][i] = (S[i]==S[j]) && (dp[j+1][i-1] && i-j>1)
* @param s
* @return
*/
public static String longestPalindrome2(String s){ if(s.equals("")) return ""; int n = s.length(); int maxLength=0; String LongestStr = ""; boolean[][] dp = new boolean[n][n]; for(int i=0;i<n;i++){ for(int j=0;j<=i;j++){ /*if(s.charAt(i)==s.charAt(j) && i-j<2) //即i=j或者i=j+1 dp[j][i]=true; if(s.charAt(i)==s.charAt(j) && dp[j+1][i-1] && i-j>1) dp[j][i]=true;*/ //这行代码太牛皮 dp[j][i] =(s.charAt(i)==s.charAt(j)) && (i-j<2 || dp[j+1][i-1]); if(dp[j][i] && maxLength<i-j+1){ maxLength=i-j+1; LongestStr = s.substring(j,i+1); } } } return LongestStr; }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
11. Container With Most Water
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, 0). Find two lines, which together with x-axis forms a container, such that the container contains the most water.
Note: You may not slant the container and n is at least 2.
The above vertical lines are represented by array [1,8,6,2,5,4,8,3,7]. In this case, the max area of water (blue section) the container can contain is 49.
Example:
Input: [1,8,6,2,5,4,8,3,7] Output: 49
- 1
- 2
/**
* 11. Container With Most Water
* Given n non-negative integers a1, a2, ..., an , where each represents a point at coordinate (i, ai).
* n vertical lines are drawn such that the two endpoints of line i is at (i, ai) and (i, 0).
* Find two lines, which together with x-axis forms a container, such that the container contains the most water.
* @param height
* @return
*/
public static int maxArea(int[] height) { if(height.length<1 || height ==null) return 0; int maxArea =0; int minval=0,j=0; for(int i=0;i<height.length;i++){ j=height.length; /*minval =Math.min(height[i],height[j]); if(minval*(j-i)>maxArea) maxArea = minval*(j-i);*/ if(i>0 && height[i]<height[i-1]) continue; while(i<j){ //包含的数值变大时才计算 if(j==height.length || (height[j]<height[j-1] && height[j]<height[i])){ minval = Math.min(height[i],height[j-1]); if(minval*(j-1-i)>maxArea) maxArea=minval*(j-1-i); } j--; } } return maxArea; }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
/**
* 11. Container With Most Water
* 优化解法二:
* 我们用两个指针分别指向数组height的两端,我们首先比较height[i]和height[j]的大小
* 如果 height[i]>height[j] 则我们保留height[i],height[j--]
* 否则,我们保留height[j],将height[i++]
* 这样做是因为,面积的大小是由更小的那个值来决定,保留更小的值,同时将更大值的指针向靠近方向移动,无论如何是得不到更大的值的
* @param height
* @return
*/
public static int maxArea2(int[] height) { int start=0,end=height.length-1; int maxVal=0; //存储面积的最大值 while(start<end){ maxVal = Math.max(Math.min(height[start],height[end])*(end-start),maxVal); //接着移动指针 if(height[start]<height[end]) start++; else end--; } return maxVal; }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
15. 3Sum
Description:
Given an array nums of n integers, are there elements a, b, c in nums such that a + b + c = 0? Find all unique triplets in the array which gives the sum of zero.
Note:
The solution set must not contain duplicate triplets.
Example:
Given array nums = [-1, 0, 1, 2, -1, -4], A solution set is: [ [-1, 0, 1], [-1, -1, 2] ]
- 1
- 2
- 3
- 4
- 5
- 6
/**
* 15. 3Sum
* Given an array nums of n integers, are there elements a, b, c
* in nums such that a + b + c = 0? Find all unique triplets in the array which gives the sum of zero.
* Note:The solution set must not contain duplicate triplets.
* Example:
* Given array nums = [-1, 0, 1, 2, -1, -4],
* A solution set is
* [[-1, 0, 1],
* [-1, -1, 2]]
* @param nums
* @return
*/
/**
* 传统的暴力解法需要O(N_3)的时间复杂度,因此我们可以这样优化算法:
* 1、先用快排,将整个数组排序
* 2、然后对于每一个排序后的元素,用两个值的和等于某个定值的方法去解
* @param nums * @return */ public static List<List<Integer>> threeSum(int[] nums) { List<List<Integer>> result = new LinkedList<List<Integer>>(); //最终输出结果 if(nums == null || nums.length<3) return result; Arrays.sort(nums); //java排序 //排序后继续检查边界 if(nums[0]>0 || nums[nums.length-1]<0) return result; for(int i=0;i<nums.length-2;i++){ if(i==0 || nums[i]!=nums[i-1]){ int low = i+1,high = nums.length-1,sum = 0-nums[i]; while(low<high){ if(nums[low]+nums[high]==sum){ result.add(Arrays.asList(nums[i],nums[low],nums[high])); while(low<high && nums[low]==nums[low+1]) low++; while(low<high && nums[high]==nums[high-1]) high--; low++;high--; }else if(nums[low]+nums[high]<sum) low++; else { high--; } } } } return result; }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
16. 3Sum Closest
Description:
Given an array nums of n integers and an integer target, find three integers in nums such that the sum is closest to target. Return the sum of the three integers. You may assume that each input would have exactly one solution.
Example:
Given array nums = [-1, 2, 1, -4], and target = 1. The sum that is closest to the target is 2. (-1 + 2 + 1 = 2).
- 1
- 2
/**
* 16. 3Sum Closest
* Given an array nums of n integers and an integer target, find three integers in nums
* such that the sum is closest to target. Return the sum of the three integers.
* You may assume that each input would have exactly one solution.
* Example:
* Given array nums = [-1, 2, 1, -4], and target = 1.
* The sum that is closest to the target is 2. (-1 + 2 + 1 = 2).
* @param nums
* @param target
* @return
*/
public static int threeSumClosest(int[] nums, int target) { Arrays.sort(nums); int result = nums[0]+nums[1]+nums[nums.length-1]; //存储最终结果 for(int i=0;i<nums.length-2;i++){ int low= i+1,high=nums.length-1; int temp = 0; while(low<high){ temp=nums[i]+nums[low]+nums[high]; if(temp>target) high--; else if(temp<target) low++; else{//相等 return target; } if(Math.abs(temp-target)<Math.abs(result-target)){ result = temp; } } } return result; }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
17. Letter Combinations of a Phone Number
Description:
Given a string containing digits from 2-9 inclusive, return all possible letter combinations that the number could represent.
A mapping of digit to letters (just like on the telephone buttons) is given below. Note that 1 does not map to any letters.
Example:
Input: "23"
Output: ["ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf"].
- 1
- 2
Note:
Although the above answer is in lexicographical order, your answer could be in any order you want.
/**
* 17. Letter Combinations of a Phone Number
* Given a string containing digits from 2-9 inclusive, return all possible letter combinations that the number could represent.
* 方法一:递归方法
* @param digits
* @return
*/
static String[] keyMapping ={"","","abc","def","ghi","jkl","mno","pqrs","tuv","wxyz"}; public static List<String> letterCombinations(String digits) { List<String> result= new LinkedList<>(); if(digits.equals("")) return result; combinationLetter("",digits,0,result); return result; } /** * 递归拼接字符串 * @param prefix 单个拼接的字符串 * @param digits 输入数字集 * @param index * @param result 结果列表 */ public static void combinationLetter(String prefix,String digits,int index,List<String> result){ //递归结束条件 if(index>=digits.length()){ result.add(prefix); return; } //取出按键对应的字符串 String letters = keyMapping[digits.charAt(index)-'0']; for(int i=0;i<letters.length();i++){ combinationLetter(prefix+letters.charAt(i), digits, index+1, result); } }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
/**
* 方法二:使用队列
* @param digits
* @return
*/
public static List<String> letterCombinations2(String digits){ List<String> result= new LinkedList<>(); if(digits.equals("")) return result; Queue<String> strQueue = new LinkedList<>(); String mapStr; strQueue.offer(""); strQueue.offer("flag"); for(int i=0;i<digits.length();i++){ mapStr = keyMapping[digits.charAt(i)-'0']; //取数字映射的字符串 while(strQueue.peek()!="flag"){ //每组字符串添加完后都加一个标记 for(int j=0;j<mapStr.length();j++){ String ch = mapStr.substring(j,j+1); strQueue.offer(strQueue.peek()+ch); } strQueue.poll(); } strQueue.offer("flag"); //在队列末尾加标记位 strQueue.poll(); //删除队列头节点 } //遍历队列 while(!strQueue.isEmpty()) result.add(strQueue.poll()); result.remove(result.size()-1); return result; }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
public static List<String> letterCombinations3(String digits){
LinkedList<String> result= new LinkedList<>();
if(digits.equals("")) return result; result.add(""); while(result.peek().length() != digits.length()){ //注意终止条件通过队列头的字符串长度来判断 String first = result.poll(); String mapStr = keyMapping[digits.charAt(first.length())-'0']; //根据取出的队列头元素的长度来查找映射字典 for(int i=0;i<mapStr.length();i++) result.offer(first+mapStr.charAt(i)); } return result; }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
19. Remove Nth Node From End of List
Description:
Given a linked list, remove the n-th node from the end of list and return its head.
Example:
Given linked list: 1->2->3->4->5, and n = 2. After removing the second node from the end, the linked list becomes 1->2->3->5.
- 1
- 2
Note:
Given n will always be valid.
- 1
Follow up:
Could you do this in one pass?
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
/**
* 19. Remove Nth Node From End of List
* Given a linked list, remove the n-th node from the end of list and return its head.
* 思路:
* 给定两个指针first,second 我们只需要first先遍历N个节点,让后两个一起开始遍历,那么当first到达尾部之后,second即为倒数第N个节点
* @param head
* @param n
* @return */ public static ListNode removeNthFromEnd(ListNode head, int n) { ListNode first=head,preCur=head; int index=n+1;//需要记录待删除节点的父节点,所以加1 //first指针先遍历n+1个节点 while(index-->0){ first = first.next; if(first==null && index>0) //index>0说明不存在待删除节点的父节点,即删除的就是头节点 return head.next; } //两个指针一起遍历 while(first!=null){ first=first.next; preCur=preCur.next; } preCur.next=preCur.next.next; return head; }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
20. Valid Parentheses
Description:
Given a string containing just the characters ‘(‘, ‘)’, ‘{‘, ‘}’, ‘[’ and ‘]’, determine if the input string is valid.
An input string is valid if:
Open brackets must be closed by the same type of brackets.
Open brackets must be closed in the correct order.
Note that an empty string is also considered valid.
Example 1:
Input: "()"
Output: true
- 1
- 2
Example 2:
Input: "()[]{}"
Output: true
- 1
- 2
Example 3:
Input: "(]"
Output: false
- 1
- 2
Example 4:
Input: "([)]"
Output: false
- 1
- 2
Example 5:
Input: "{[]}"
Output: true
- 1
- 2
/**
* 20. Valid Parentheses
* Given a string containing just the characters '(', ')', '{', '}', '[' and ']', determine if the input string is valid.
* An input string is valid if:
* Open brackets must be closed by the same type of brackets.
* Open brackets must be closed in the correct order.
* Note that an empty string is also considered valid.
* Example 1:
* Input: "()"
* Output: true
* @param s
* @return
*/
public static boolean isValid(String s) { if(s==null || s.isEmpty()) return true; //初始化一个栈 Stack<Character> stack = new Stack<>(); for(int i=0;i<s.length();i++){ Character ch = s.charAt(i); if(!stack.isEmpty()){ if((stack.peek()=='('&& ch==')') || (stack.peek()=='['&& ch==']') || (stack.peek()=='{'&& ch=='}')){ stack.pop(); continue; } } stack.push(ch); } return stack.isEmpty(); }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
21. Merge Two Sorted Lists
Description:
Merge two sorted linked lists and return it as a new list. The new list should be made by splicing together the nodes of the first two lists.
Example:
Input: 1->2->4, 1->3->4 Output: 1->1->2->3->4->4
- 1
- 2
/**
* 21. Merge Two Sorted Lists
* Merge two sorted linked lists and return it as a new list.
* The new list should be made by splicing together the nodes of the first two lists.
* Example:
* Input: 1->2->4, 1->3->4
* Output: 1->1->2->3->4->4
* @param l1
* @param l2
* @return
*/
public static ListNode mergeTwoLists(ListNode l1, ListNode l2){ ListNode p1=l1,p2=l2; ListNode phead = new ListNode(-1); //创建头结点 ListNode index=phead; while(p1!=null && p2!=null){ if(p1.val<=p2.val){ index.next=p1; p1=p1.next; index=index.next; }else{ index.next=p2; p2=p2.next; index=index.next; } } if(p1!=null) index.next=p1; if(p2!=null) index.next=p2; return phead.next; } public List<String> generateParenthesis(int n) { return generate("",n,0,0); }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
22. Generate Parentheses
Description:
Given n pairs of parentheses, write a function to generate all combinations of well-formed parentheses.
For example, given n = 3, a solution set is:
[
"((()))",
"(()())",
"(())()",
"()(())",
"()()()" ]
- 1
- 2
- 3
- 4
- 5
- 6
- 7
/**
* 22. Generate Parentheses
* Given n pairs of parentheses, write a function to generate all combinations of well-formed parentheses.
* @param parenthese
* @param num
* @param left 左括号数
* @param right 右括号数 * @return */ public static List<String> generate(String parenthese,int num,int left,int right){ List<String> result = new ArrayList<String>(); if(left < num){ //生成的左括号数大于右括号数,则下一个括号可以为左括号,也可以为右括号 if(left>right){ result.addAll(generate(parenthese+"(",num,left+1,right)); result.addAll(generate(parenthese+")",num,left,right+1)); } else{ //左括号数和右括号数相同时,一定是添加左括号 result.addAll(generate(parenthese+"(",num,left+1,right)); } } if(left==num &&right<num){ for(int i=right+1;i<=num;i++) parenthese += ")"; right = num; result.add(parenthese); } return result; }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
23. Merge k Sorted Lists
Description:
Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity.
Example:
Input:
[
1->4->5, 1->3->4, 2->6 ] Output: 1->1->2->3->4->4->5->6
- 1
- 2
- 3
- 4
- 5
- 6
- 7
解法一:
/**
* 23. Merge k Sorted Lists
* Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity.
* Example:
* Input:
* [
* 1->4->5,
* 1->3->4,
* 2->6
* ]
* Output: 1->1->2->3->4->4->5->6
* Approach 2: Compare one by one
* Time complexity : O(kN)where k is the number of linked lists.
* @param lists
* @return
*/
public static ListNode mergeKLists(ListNode[] lists){ if(lists==null || lists.length<1) return null; ListNode head = new ListNode(-1); ListNode phead =head; int count=0,index=0,min; //奇数已经遍历完的链表 while(count<lists.length){ //找出K个链表的头结点值最小的那一个 count=0; min = Integer.MAX_VALUE; for(int i=0;i<lists.length;i++){ if(lists[i]==null){ count++; continue; } if(lists[i].val<min){ min = lists[i].val; index=i; } } if(count==lists.length) break; phead.next=lists[index]; phead=phead.next; lists[index]=lists[index].next; } return head.next; }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
解法二:
/**
* Approach 3: Optimize Approach 2 by Priority Queue
* @param lists
* @return
*/
public static ListNode mergeKLists2(ListNode[] lists){ ListNode head = new ListNode(-1); ListNode phead = head; //构造优先队列 Queue<ListNode> minheap = new PriorityQueue<ListNode>(new Comparator<ListNode>() { @Override public int compare(ListNode o1, ListNode o2) { if(o1.val<o2.val) return -1; else if(o1.val==o2.val) return 0; else { return 1; } } }); //初始化优先队列 for(ListNode l:lists){ if(l!=null) minheap.add(l); } while(!minheap.isEmpty()){ phead.next=minheap.poll(); //队列的头元素必为所有链表头元素中的最小值 phead=phead.next; if(phead.next!=null) minheap.add(phead.next); } return head.next; }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
解法三:
/**
* 与归并排序的思路相似
* @param lists
* @return
*/
public static ListNode mergeKLists3(ListNode[] lists){ int length=lists.length; int inteval=1; while(inteval<length){ for(int i=0;i<length-inteval;i+=inteval*2){ lists[i] = mergeTwoLists(lists[i],lists[i+inteval]); } inteval *=2; } return lists[0]; }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
32. Longest Valid Parentheses
Description:
Given a string containing just the characters ‘(’ and ‘)’, find the length of the longest valid (well-formed) parentheses substring.
Example 1:
Input: "(()"
Output: 2 Explanation: The longest valid parentheses substring is "()"
- 1
- 2
- 3
Example 2:
Input: ")()())"
Output: 4 Explanation: The longest valid parentheses substring is "()()"
- 1
- 2
- 3
/**
* 32. Longest Valid Parentheses
* Given a string containing just the characters '(' and ')', find the length of the longest valid (well-formed) parentheses substring
* 思路:利用栈
* 首先向入栈元素-1,作为栈底元素,接着对于遍历到的字符串元素“(”或")",我们有两种处理方式:
* 1)如果是“(”,则直接入栈
* 2)如果是“)”,则要考虑两种情况:
* 第一种为:如果此时栈里面多于一个元素,则说明栈顶一定是“(”,我们只需要出栈此元素,并记录合格的字符串长度就可以了
* 第二种为:栈顶只有一个元素(“)”或-1),此时我们只需要栈顶元素出栈,并将“)”入栈就可以了
* Example 1:
* Input: "(()"
* Output: 2
* Explanation: The longest valid parentheses substring is "()"
* @param s
* @return
*/
public static int longestValidParentheses(String s) { if(s==null || s.equals("")) return 0; //初始化一个栈 Stack<Integer> stack = new Stack<>(); stack.push(-1); int max=0; int count=0; //计数,将匹配的括号对数记下来 for(int i=0;i<s.length();i++){ char ch = s.charAt(i); //如果是“(”,就用栈记录下他的索引 if(ch=='(') stack.push(i); else{ //如果是“)”,则分为两种情况:栈的元素多余一个,这时肯定可以配对;2)栈里面只有一个元素,此时可以肯定是不能配对的 stack.pop(); if(!stack.isEmpty()){ count = i-stack.peek(); max = (max<count)? count:max; }else{ stack.push(i); } } } return max; }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
/**
* 动态规划解法
* 用dp[i]来表示以i结束的字符串的最长合格字符串的长度,那么很明显“(”对应的都为0
* @return
*
*/
public static int longestValidParentheses2(String s){ //边界条件 if(s==null || s.equals("")) return 0; int max =0,index=0;; int[] dp = new int[s.length()]; for(int i=1;i<s.length();i++){ char ch = s.charAt(i); if(ch == ')' && s.charAt(i-1)=='('){ //只更新")"的情况 //第一种情况,前一个 index = i-2; if(index>=0) dp[i]=dp[i-2]+2; else dp[i]=2; } if(ch == ')' && s.charAt(i-1)==')'){ index = i-dp[i-1]-1; if(index>0 && s.charAt(index)=='(') dp[i]=dp[i-1]+dp[index-1]+2; // else if(index==0 && s.charAt(index)=='(') dp[i]=dp[i-1]+2; else { dp[i]=0; } } max = max<dp[i] ? dp[i]:max; } return max; }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
33. Search in Rotated Sorted Array
Description:
Suppose an array sorted in ascending order is rotated at some pivot unknown to you beforehand.
(i.e., [0,1,2,4,5,6,7] might become [4,5,6,7,0,1,2]).
You are given a target value to search. If found in the array return its index, otherwise return -1.
You may assume no duplicate exists in the array.
Your algorithm’s runtime complexity must be in the order of O(log n).
Example 1:
Input: nums = [4,5,6,7,0,1,2], target = 0 Output: 4
- 1
- 2
Example 2:
Input: nums = [4,5,6,7,0,1,2], target = 3 Output: -1
- 1
- 2
解法一:
/**
* 33. Search in Rotated Sorted Array
* Suppose an array sorted in ascending order is rotated at some pivot unknown to you beforehand.
* @param nums
* @param target
* @return
*/
public static int search(int[] nums, int target){ if(nums==null || nums.length<1) return -1; //查找支点 int index=0,result=-1; for(;index+1<nums.length;index++){ if(nums[index]>nums[index+1]) break; } if(nums[0]<target){ result=BinarySearch(nums,0,index,target); }else if(nums[0]>target) result=BinarySearch(nums,index+1,nums.length-1,target); else { return 0; } return result; } private static int BinarySearch(int[] nums,int start,int end,int target) { int mid=(start+end)/2; if(start<=end){ if(nums[mid]<target) return BinarySearch(nums,mid+1,end,target); else if(nums[mid]>target) return BinarySearch(nums, start,mid-1,target); else return mid; }else{ return -1; } }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
解法二:
public static int search2(int[] nums, int target){ if(nums==null || nums.length<1) return -1; //查找支点 int low=0,high=nums.length-1; while(low<=high){ int mid=low+(high-low)/2; if(nums[mid]==target) return mid; //先区分mid的位置 if(nums[mid]>=nums[low]){ if(nums[low]<=target && target<nums[mid]) high=mid-1; else low=mid+1; }else{ if(target<=nums[high] && target>nums[mid]) low = mid+1; else high=mid-1; } } return -1; }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
34. Find First and Last Position of Element in Sorted Array
Description:
Given an array of integers nums sorted in ascending order, find the starting and ending position of a given target value.
Your algorithm’s runtime complexity must be in the order of O(log n).
If the target is not found in the array, return [-1, -1].
Example 1:
Input: nums = [5,7,7,8,8,10], target = 8 Output: [3,4]
- 1
- 2
Example 2:
Input: nums = [5,7,7,8,8,10], target = 6 Output: [-1,-1]
- 1
- 2
解法一:
/**
* 34. Find First and Last Position of Element in Sorted Array
* @param nums
* @param target
* @return
*/
public static int[] searchRange(int[] nums, int target) { int low=0,high=nums.length-1; int first=0,last=0; int[] result = {-1,-1}; while(low<=high){ int mid = (low+high)/2; if(nums[mid]<target) low=mid+1; else if(nums[mid]>target) high=mid-1; else { //从mid处向前后查找 first=mid;last=mid; while(first>=0){ if(nums[first]!=nums[mid]) break; first--; } result[0]=first+1; while(last<nums.length){ if(nums[last]!=nums[mid]) break; last++; } result[1]=last-1; } } return result; }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
解法二:
/**
* 34. Find First and Last Position of Element in Sorted Array
* 解法二
* @param nums
* @param target
* @return
*/
public static int[] searchRange2(int[] nums, int target) { int[] result = {-1,-1}; if(nums==null) return result; result[0]=GetFirstTarget(nums, target); result[1]=GetLastTarget(nums, target); return result; } /** * 找出nums中第一个target的位置 * @param nums * @param target * @return */ public static int GetFirstTarget(int[] nums,int target){ int low=0,high=nums.length-1; int result=-1; while(low<=high){ int mid = (low+high)/2; if(nums[mid]==target){ if(mid>0 && nums[mid-1]!=target || mid==0){ result=mid; break; } high=mid-1; }else if(nums[mid]>target) high=mid-1; else { low = mid+1; } } return result; } /** * 找出nums中最后一个target的位置 * @param nums * @param target * @return */ public static int GetLastTarget(int[] nums,int target){ int low=0,high=nums.length-1; int result=-1; while(low<=high){ int mid = (low+high)/2; if(nums[mid]==target){ if(mid<nums.length-1 && nums[mid+1]!=target || mid==nums.length-1){ result=mid; break; } low=mid+1; }else if(nums[mid]>target) high=mid-1; else { low = mid+1; } } return result; }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
35. Search Insert Position
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.
Example 1:
Input: [1,3,5,6], 5 Output: 2
- 1
- 2
Example 2:
Input: [1,3,5,6], 2 Output: 1
- 1
- 2
Example 3:
Input: [1,3,5,6], 7 Output: 4
- 1
- 2
Example 4:
Input: [1,3,5,6], 0 Output: 0
- 1
- 2
解法一:
/**
* 35. Search Insert Position
* Given a sorted array and a target value, return the index if the target is found.
* If not, return the index where it would be if it were inserted in order.
* Example 1:
* Input: [1,3,5,6], 5
* Output: 2
* Example 2:
* Input: [1,3,5,6], 2
* Output: 1
* Example 3:
* Input: [1,3,5,6], 7
* Output: 4
* Example 4:
* Input: [1,3,5,6], 0
* Output: 0
* @param nums
* @param target
* @return
*/
public static int searchInsert(int[] nums, int target){ if(nums==null || nums.length<1) return 0; int index=0; for(;index<nums.length;index++){ if(nums[index]>=target){ break; } } return index; }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
解法二:
public static int searchInsert1(int[] nums, int target) { if(nums==null || nums.length<1) return 0; int low = 0, high = nums.length-1; // Invariant: the desired index is between [low, high+1] while (low <= high) { int mid = low + (high-low)/2; if (nums[mid] < target) low = mid+1; else if(nums[mid] >target) high = mid-1; else { return mid; } } // (1) At this point, low > high. That is, low >= high+1 // (2) From the invariant, we know that the index is between [low, high+1], so low <= high+1. Follwing from (1), now we know low == high+1. // (3) Following from (2), the index is between [low, high+1] = [low, low], which means that low is the desired index // Therefore, we return low as the answer. You can also return high+1 as the result, since low == high+1 return low; }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
39. Combination Sum
Description:
Given a set of candidate numbers (candidates) (without duplicates) and a target number (target), find all unique combinations in candidates where the candidate numbers sums to target.
The same repeated number may be chosen from candidates unlimited number of times.
Note:
All numbers (including target) will be positive integers.
The solution set must not contain duplicate combinations.
Example 1:
Input: candidates = [2,3,6,7], target = 7, A solution set is: [ [7], [2,2,3] ]
- 1
- 2
- 3
- 4
- 5
- 6
Example 2:
Input: candidates = [2,3,5], target = 8, A solution set is: [ [2,2,2,2], [2,3,3], [3,5] ]
- 1
- 2
- 3
- 4
- 5
- 6
- 7
/**
* 39. Combination Sum
* Given a set of candidate numbers (candidates) (without duplicates) and a
* target number (target), find all unique combinations in candidates where the candidate numbers sums to target.
* @param args
*/
public List<List<Integer>> combinationSum(int[] candidates, int target) { List<List<Integer>> result = new ArrayList<List<Integer>>(); if(candidates == null || candidates.length<1) return result; //DFS combinationSum(candidates,target,0,new ArrayList<>(),result); return result; } /** * DFS算法计算数组中和为target的所有组合 * @param candidates 数组 * @param target 目标值 * @param i 当前遍历到的数组索引 * @param record 临时记录列表 * @param result 最终返回列表 */ private void combinationSum(int[] candidates, int target, int index, List<Integer> record, List<List<Integer>> result) { if(target<0) return; if(target == 0){ result.add(record); return; } for(int i=index;i<candidates.length;i++){ target -=candidates[i]; //将candidates[i]加入target record.add(candidates[i]); combinationSum(candidates,target,i,record,result); target +=candidates[i]; //典型的回溯法结构 record.remove(record.size()-1); } }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
42. Trapping Rain Water
Description:
Given n non-negative integers representing an elevation map where the width of each bar is 1, compute how much water it is able to trap after raining.
The above elevation map is represented by array [0,1,0,2,1,0,1,3,2,1,2,1]. In this case, 6 units of rain water (blue section) are being trapped. Thanks Marcos for contributing this image!
Example:
Input: [0,1,0,2,1,0,1,3,2,1,2,1] Output: 6
- 1
- 2
解法一:
/**
* 42. Trapping Rain Water
* Given n non-negative integers representing an elevation map
* where the width of each bar is 1, compute how much water it is able to trap after raining.
* 思路:
* 首先我们将当前的height[i]记录为front=height[i](假设能构成容器的前端高度)。那么对于height[i+1],我们只考虑两种情况:
* 情况一:height[i+1]>=height[i]
* 此时,二者没有构成容器的可能,故我们可以置front=height[i+1],并记录下此时的索引frontIndex=i+1;
* 情况二:height[i+1]<height[i]
* 此时,二者有构成容器的可能,我们记录下可以容水的容积temp+=front-height[i+1],并继续遍历height[i+2]...height[length-1],
* 如果其中遇到某个height[j]>=front,则我们将容积temp记录到总容积max中去,并将front=height[j],frontIndex=j;max+=temp;temp=0;
* 有一种特殊的情况就是当最后一个高度height[length-1]<front的时候,此时前面的解法存在问题,此时我们对于height[frontIndex]....height[length]
* 要重新考虑,我们只需每一次将front--,并继续遍历就可以了
* @param height
* @return
*/
public static int trap(int[] height){ if(height==null || height.length<3) return 0; int max =0;//用于记录最大的储水容积 int front=height[0],frontIndex=0; //front表示容器的前端高度,back表示构成容器的后端高度 int temp=0; for(int i=1;i<height.length;i++){ if(height[i]>=front){ //如果height>=front,则可以构成容器 front=height[i]; // frontIndex=i; max+=temp; //将temp值添加到总的容积max temp=0; //并将temp置为0 } else{ temp+=front-height[i]; //temp记录某个容器的容积 } //对最后的高度要进行判断,如果height[length-1]<front,则说明构不成容器,此时将front-- if(i==height.length-1 && height[i]<front){ temp=0; front--; i=frontIndex; } } return max; }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
解法二:
/**
* 解法二:
* 采用动态规划的思想将index位置的左边(i<=index)的最高值和右边(i>index)的最高值记录下来
* @param height
* @return
*/
public static int trap2(int[] height){ if(height==null || height.length<3) return 0; int[] leftMax = new int[height.length]; int[] rightMax = new int[height.length]; int water=0; leftMax[0]=height[0]; for(int i=1;i<height.length;i++){ leftMax[i] = Math.max(height[i],leftMax[i-1]); } rightMax[height.length-1]=height[height.length-1]; for(int j=height.length-2;j>=0;j--) rightMax[j]=Math.max(height[j],rightMax[j+1]); for(int i=1;i<height.length-1;i++) water+=Math.min(leftMax[i],rightMax[i])-height[i]; return water; }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
46. Permutations
Description:
Given a collection of distinct integers, return all possible permutations.
Example:
Input: [1,2,3] Output: [ [1,2,3], [1,3,2], [2,1,3], [2,3,1], [3,1,2], [3,2,1] ]
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
/**
* 46. Permutations
* Given a collection of distinct integers, return all possible permutations.
* Example:
* Input: [1,2,3]
* Output:
* [[1,2,3],
* [1,3,2],
* [2,1,3],
* [2,3,1],
* [3,1,2],
* [3,2,1]]
* 思路:把数组分为两部分,第一个数字为前一部分,其他为后一部分,依次交换;
* 然后采用递归的思路
* @param nums
* @return
*/
public static List<List<Integer>> permute(int[] nums) { //初始化链表 List<List<Integer>> result = new LinkedList<>(); if(nums==null || nums.length<1) return result; //int[] copy = Arrays.copyOf(nums,nums.length); allPermute(nums,0,result); return result; } /** * 递归思路 * @param array * @param startIndex 指数组要替换的那个位置 * @param result */ public static void allPermute(int[] array,int startIndex,List<List<Integer>> result){ if(startIndex == array.length){ List<Integer> sublist = new LinkedList<>(); for(int i=0;i<array.length;i++) sublist.add(array[i]); result.add(sublist); return; } int temp =array[startIndex]; for(int i=startIndex;i<array.length;i++){ if(i==startIndex) allPermute(array,startIndex+1, result); else{ //先替换 array[startIndex]=array[i]; array[i]=temp; allPermute(array,startIndex+1, result); //然后再换过来 array[i]=array[startIndex]; array[startIndex]=temp; } } }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
48. Rotate Image
Description:
You are given an n x n 2D matrix representing an image.
Rotate the image by 90 degrees (clockwise).
Note:
You have to rotate the image in-place, which means you have to modify the input 2D matrix directly. DO NOT allocate another 2D matrix and do the rotation.
Example 1:
Given input matrix =
[
[1,2,3],
[4,5,6], [7,8,9] ], rotate the input matrix in-place such that it becomes: [ [7,4,1], [8,5,2], [9,6,3] ]
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
Example 2:
Given input matrix =
[
[ 5, 1, 9,11], [ 2, 4, 8,10], [13, 3, 6, 7], [15,14,12,16] ], rotate the input matrix in-place such that it becomes: [ [15,13, 2, 5], [14, 3, 4, 1], [12, 6, 8, 9], [16, 7,10,11] ]
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
/**
* 48. Rotate Image
* You are given an n x n 2D matrix representing an image.Rotate the image by 90 degrees (clockwise).
* Example 1:
* Given input matrix =
* [
* [1,2,3],
* [4,5,6],
* [7,8,9]
* ],rotate the input matrix in-place such that it becomes:
* [
* [7,4,1],
* [8,5,2],
* [9,6,3]
* ]
* @param matrix
*/
/**
* 思路,从最外面一层一次向里层遍历,每一次将4条边上对应的位置依次互换即可
* @param matrix
*/
public void rotate(int[][] matrix) { int len = matrix.length; for(int i=0;i<len/2;++i){ //i表示遍历的圈数 for(int j=i;j<len-i-1;++j){ //j表示第i圈上元素的索引的范围 int tmp = matrix[i][j]; matrix[i][j] = matrix[len-j-1][i]; //替换上边的元素 matrix[len-j-1][i] = matrix[len-i-1][len-j-1]; //替换左边上的元素 matrix[len-i-1][len-j-1] = matrix[j][len-i-1]; matrix[j][len-i-1] = tmp; } } }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
49. Group Anagrams
Description:
Given an array of strings, group anagrams together.
Example:
Input: ["eat", "tea", "tan", "ate", "nat", "bat"], Output: [ ["ate","eat","tea"], ["nat","tan"], ["bat"] ]
- 1
- 2
- 3
- 4
- 5
- 6
- 7
Note:
- All inputs will be in lowercase.
- The order of your output does not matter.
解法一:
/**
* 49. Group Anagrams
* Given an array of strings, group anagrams together.
* Example:
* Input: ["eat", "tea", "tan", "ate", "nat", "bat"],
* Output:
* [
* ["ate","eat","tea"],
* ["nat","tan"],
* ["bat"]
* ]
* Note:
* All inputs will be in lowercase.
* The order of your output does not matter.
* @param strs
* @return
*/
/**
* 解法一:暴力解法(时间复杂度太大)
**/
public List<List<String>> groupAnagrams(String[] strs) { // String flag="-1"; //flag用来标记已经访问过的数组元素 List<List<String>> result = new LinkedList<>(); if(strs==null || strs.length<1) return result; for(int i=0;i<strs.length;i++){ if(!strs[i].equals(flag)){ List<String> temp = new LinkedList<>(); for(int j=i+1;j<strs.length;j++){ if(!strs[j].equals(flag) && isAnagrams(strs[i],strs[j])){ //如果二者是重组字 temp.add(strs[j]); strs[j]=flag; } } temp.add(strs[i]); strs[i]=flag; result.add(temp); } } return result; } /** * 判断两个字符串是否是Anagrams * @param string * @param string2 * @return */ private boolean isAnagrams(String string, String string2) { if(string==null || string2==null || string.length()!=string2.length()) return false; else{ StringBuffer compare = new StringBuffer(string2); for(int i=0;i<string.length();i++){ String ch = string.substring(i,i+1); if(!compare.toString().contains(ch)) return false; int index = compare.indexOf(ch); compare.delete(index,index+1); } } return true; }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
解法二:
/**
* 解法二:将数组中的字符串排序,那么是anagrams的字符串排序之后一定是相同的
* 时间复杂度(NKLOG(K))
* @param strs
* @return
*/
public List<List<String>> groupAnagrams2(String[] strs) { HashMap<String,List<String>> map = new HashMap<>(); if(strs==null || strs.length<1) return new ArrayList<>(); for(int i=0;i<strs.length;i++){ char[] ch = strs[i].toCharArray(); Arrays.sort(ch); String key = String.valueOf(ch); if(!map.containsKey(key)) map.put(key,new ArrayList<String>()); map.get(key).add(strs[i]); } return new ArrayList<>(map.values()); }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
解法三:
/**
* 解法三:用26个字母对应的数组来计数每一个字母出现的次数,则次数相同的一定是Anagrams
* @param args
*/
public List<List<String>> groupAnagrams3(String[] strs){
HashMap<String,List<String>> map = new HashMap<>(); if(strs==null || strs.length<1) return new ArrayList<>(); int[] count = new int[26]; for(int i=0;i<strs.length;i++){ Arrays.fill(count,0); for(char ch:strs[i].toCharArray()) count[ch-'a']++; StringBuffer sb = new StringBuffer(); for(int j=0;j<26;j++){ sb.append('#'); sb.append(count[j]); } String key = sb.toString(); //注意要转换成String,否则StringBuffer不能比较字符串 if(!map.containsKey(key)) map.put(key,new ArrayList<>()); map.get(key).add(strs[i]); } return new ArrayList<>(map.values()); }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
53. Maximum Subarray
Description:
Given an integer array nums, find the contiguous subarray (containing at least one number) which has the largest sum and return its sum.
Example:
Input: [-2,1,-3,4,-1,2,1,-5,4], Output: 6 Explanation: [4,-1,2,1] has the largest sum = 6.
- 1
- 2
- 3
Follow up:
If you have figured out the O(n) solution, try coding another solution using the divide and conquer approach, which is more subtle.
/**
* 53. Maximum Subarray
* Given an integer array nums, find the contiguous subarray (containing at least one number) which has the largest sum and return its sum.
* Example:
* Input: [-2,1,-3,4,-1,2,1,-5,4],
* Output: 6
* Explanation: [4,-1,2,1] has the largest sum = 6.
* @param nums
* @return
*/
public int maxSubArray(int[] nums) { if(nums==null || nums.length<1) return 0; int max=nums[0],temp=nums[0]; //temp用于计算nums[i]之前的连续数组的和最大值 for(int i=1;i<nums.length;i++){ if(temp<0) //num[i]之前的连续数组之和大于0,则继续寻找连续子数组,如果小于等于0,则重新赋值计算,并将之前的最大值存储下来 temp=0; temp+=nums[i]; max = (max>=temp)? max:temp; } return max; }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
55. Jump Game
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.
Determine if you are able to reach the last index.
Example 1:
Input: [2,3,1,1,4] Output: true Explanation: Jump 1 step from index 0 to 1, then 3 steps to the last index.
- 1
- 2
- 3
Example 2:
Input: [3,2,1,0,4] Output: false Explanation: You will always arrive at index 3 no matter what. Its maximum jump length is 0, which makes it impossible to reach the last index.
- 1
- 2
- 3
- 4
解法一:
/**
* 55. Jump Game
* 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.
* Determine if you are able to reach the last index.
* Example 1:
* Input: [2,3,1,1,4]
* Output: true
* Explanation: Jump 1 step from index 0 to 1, then 3 steps to the last index.
* @param nums
* @return
*/
public boolean canJump(int[] nums) { if(nums==null || nums.length<1) return false; if(nums.length>1){ int farIndex =0; //记录可以跳到的最远的INdex for(int i=0;i<nums.length;i++){ if(i>=farIndex && nums[i]==0 && i!=nums.length-1) //注意最后一步为0的情况 return false; else farIndex = Math.max(farIndex,i+nums[i]); } } return true; }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
/**
* 解法二:倒序
* @param nums
* @return
*/
public boolean canJump2(int[] nums) { int lastIndex = nums.length - 1; for(int i = nums.length - 2; i>=0; i--){ if(nums[i]+i>=lastIndex){ lastIndex = i; } } return lastIndex == 0; }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
拓展:
45. Jump Game II
/**
* 45. Jump Game II
* Given an array of non-negative integers, you are initially positioned at the first index of the array.
* Each element in the array represents your maximum jump length at that position.
* Your goal is to reach the last index in the minimum number of jumps.
* Example:
* Input: [2,3,1,1,4]
* Output: 2
* Explanation: The minimum number of jumps to reach the last index is 2.
* Jump 1 step from index 0 to 1, then 3 steps to the last index.
* Note:
* You can assume that you can always reach the last index.
* @param nums
* @return
*/
/**
* 解法一:暴力解法,用DFS,时间复杂度超了
*/
public int minstep; public int jumpII(int[] nums){ minstep=nums.length; getAllPossibleSteps(nums,0,0); return minstep; } /** * 计算所有可能的到达最后一步的步数 * @param nums * @param curPostion 当前所在的位置 * @param count目前跳的步数 * @param minstep 最小的步数 */ private void getAllPossibleSteps(int[] nums,int curPostion,int count){ if(curPostion>=nums.length-1){ minstep = count; return; } for(int i=nums[curPostion];i>0;i--){ if(count>=minstep) break; getAllPossibleSteps(nums,curPostion+i,count+1); } } /** * 解法二: * 每一次在能跳到的范围之内选择下一次跳得最远的点为候选的跳点,这样跳的次数应该最少 * @param nums * @return */ public int jumpII2(int[] nums){ int count=0,curPostion=0; //当前所在的位置 while(curPostion<nums.length-1){ count++; if(curPostion+nums[curPostion]>=nums.length-1) break; else curPostion = getNexPositon(nums,curPostion); //下一个最合适的跳点 } return count; } /** * 计算能跳到的范围之内的最适合的跳点 * @param nums * @param curPostion * @return */ private int getNexPositon(int[] nums, int curPostion) { int candiPostion =curPostion+1; //候选的跳点位置 int farestPotion =curPostion; //下一步能够跳到的最远的位置 for(int i= curPostion+1;i<=curPostion+nums[curPostion];i++){ if(i+nums[i]>farestPotion){ candiPostion=i; farestPotion = i+nums[i]; } } return candiPostion; } /** * 解法三: * The main idea is based on greedy. Let's say the range of the current jump is [curBegin, curEnd], * curFarthest is the farthest point that all points in [curBegin, curEnd] can reach. * Once the current point reaches curEnd, then trigger another jump, * and set the new curEnd with curFarthest, then keep the above steps, as the following: * @param A * @return */ public int jumpII3(int[] A) { int jumps = 0, curEnd = 0, curFarthest = 0; for (int i = 0; i < A.length - 1; i++) { curFarthest = Math.max(curFarthest, i + A[i]); if (i == curEnd) { jumps++; curEnd = curFarthest; } } return jumps; }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
56. Merge Intervals
Description:
Given a collection of intervals, merge all overlapping intervals.
Example 1:
Input: [[1,3],[2,6],[8,10],[15,18]] Output: [[1,6],[8,10],[15,18]] Explanation: Since intervals [1,3] and [2,6] overlaps, merge them into [1,6].
- 1
- 2
- 3
Example 2:
Input: [[1,4],[4,5]] Output: [[1,5]] Explanation: Intervals [1,4] and [4,5] are considerred overlapping.
- 1
- 2
- 3
/**
* Definition for an interval.
* public class Interval {
* int start;
* int end;
* Interval() { start = 0; end = 0; } * Interval(int s, int e) { start = s; end = e; } * } */ /** * 56. Merge Intervals * Given a collection of intervals, merge all overlapping intervals.合并所有的重叠间隔 * Example 1: * Input: [[1,3],[2,6],[8,10],[15,18]] * Output: [[1,6],[8,10],[15,18]] * Explanation: Since intervals [1,3] and [2,6] overlaps, merge them into [1,6]. * Example 2: * Input: [[1,4],[4,5]] * Output: [[1,5]] * Explanation: Intervals [1,4] and [4,5] are considerred overlapping. * 思路: * 首先根据间隔的start值将集合重新排序,然后再进行合并 * @param intervals * @return */ public List<Interval> merge(List<Interval> intervals){ List<Interval> result = new ArrayList<Interval>(); if(intervals == null || intervals.size()<1) return result; //对列表排序 Collections.sort(intervals,new Comparator<Interval>() { public int compare(Interval o1, Interval o2) { return o1.start-o2.start; } }); int start=intervals.get(0).start,end=intervals.get(0).end; for(int i=1;i<intervals.size();i++){ if(intervals.get(i).start<=end){ end = Math.max(end,intervals.get(i).end); } else{ result.add(new Interval(start,end)); start = intervals.get(i).start; end = intervals.get(i).end; } } result.add(new Interval(start,end)); return result; }