leetcode解题记录
Practice 1:
题目描述:
给定一个整数数组和一个目标值,找出数组中和为目标值的两个数。
你可以假设每个输入只对应一种答案,且同样的元素不能被重复利用。
示例:
给定 nums = [2, 7, 11, 15], target = 9
因为 nums[0] + nums[1] = 2 + 7 = 9
所以返回 [0, 1]
我的解答:
1 class Solution { 2 public int[] twoSum(int[] nums, int target) { 3 int [] array = nums; 4 int sum = target; 5 int second; 6 int first; 7 for (int i = 0; i < array.length; i++) { 8 first = array[i]; 9 second = sum - first; 10 for (int j = i+1; j <array.length ; j++) { 11 if (second == array[j]){ 12 return new int[] {i,j}; 13 } 14 } 15 } 16 return null; 17 } 18 }
更优解答案解析:
两遍哈希表
1 public int[] twoSum(int[] nums, int target) { 2 Map<Integer, Integer> map = new HashMap<>(); 3 for (int i = 0; i < nums.length; i++) { 4 map.put(nums[i], i); 5 } 6 for (int i = 0; i < nums.length; i++) { 7 int complement = target - nums[i]; 8 if (map.containsKey(complement) && map.get(complement) != i) { 9 return new int[] { i, map.get(complement) }; 10 } 11 } 12 throw new IllegalArgumentException("No two sum solution"); 13 }
-
时间复杂度:O(n), 我们把包含有 nn 个元素的列表遍历两次。由于哈希表将查找时间缩短到 O(1)) ,所以时间复杂度为 O(n)。
-
空间复杂度:O(n), 所需的额外空间取决于哈希表中存储的元素数量,该表中存储了 n 个元素。
Practice 2:
给定两个非空链表来表示两个非负整数。位数按照逆序方式存储,它们的每个节点只存储单个数字。将两数相加返回一个新的链表。
你可以假设除了数字 0 之外,这两个数字都不会以零开头。
示例:
输入:(2 -> 4 -> 3) + (5 -> 6 -> 4)
输出:7 -> 0 -> 8
原因:342 + 465 = 807
我的解答:
这道题自己没有做出来,在看完解答后,按答案的方式做了一遍。
1 /** 2 * Definition for singly-linked list. 3 * public class ListNode { 4 * int val; 5 * ListNode next; 6 * ListNode(int x) { val = x; } 7 * } 8 */ 9 class Solution { 10 public ListNode addTwoNumbers(ListNode l1, ListNode l2) { 11 ListNode head = new ListNode(0); 12 ListNode curr = head; 13 ListNode p = l1; 14 ListNode q = l2; 15 int carry = 0; 16 int sum = 0; 17 while (p != null || q != null) { 18 int x = (p!=null)?p.val:0; 19 int y = (q!=null)?q.val:0; 20 sum = x+y+carry; 21 carry = sum/10; 22 curr.next = new ListNode(sum%10); 23 curr = curr.next; 24 if(p!=null) 25 p=p.next; 26 if(q!=null) 27 q=q.next; 28 29 } 30 if(carry>0){ 31 curr.next = new ListNode(1); 32 } 33 34 35 return head.next; 36 } 37 }
Practice 3
给定一个字符串,找出不含有重复字符的最长子串的长度。
示例:
给定 "abcabcbb"
,没有重复字符的最长子串是 "abc"
,那么长度就是3。
给定 "bbbbb"
,最长的子串就是 "b"
,长度是1。
给定 "pwwkew"
,最长子串是 "wke"
,长度是3。请注意答案必须是一个子串,"pwke"
是 子序列 而不是子串。
我的解答错误
答案解析:
(一)暴力法
逐个检查所有的子字符串,看它是否不含有重复的字符。
1 public class Solution { 2 public int lengthOfLongestSubstring(String s) { 3 int n = s.length(); 4 int ans = 0; 5 for (int i = 0; i < n; i++) 6 for (int j = i + 1; j <= n; j++) 7 if (allUnique(s, i, j)) ans = Math.max(ans, j - i); 8 return ans; 9 } 10 11 public boolean allUnique(String s, int start, int end) { 12 Set<Character> set = new HashSet<>(); 13 for (int i = start; i < end; i++) { 14 Character ch = s.charAt(i); 15 if (set.contains(ch)) return false; 16 set.add(ch); 17 } 18 return true; 19 } 20 }
(二)滑动窗口
滑动窗口是数组/字符串问题中常用的抽象概念。 窗口通常是在数组/字符串中由开始和结束索引定义的一系列元素的集合,即 [i, j)左闭,右开)。而滑动窗口是可以将两个边界向某一方向“滑动”的窗口。例如,我们将 [i, j)向右滑动 1个元素,则它将变为 [i+1, j+1)(左闭,右开)。
使用 HashSet 将字符存储在当前窗口 [i, j)(最初 j = i)中。 然后我们向右侧滑动索引 j,如果它不在 HashSet 中,我们会继续滑动 j。直到 s[j] 已经存在于 HashSet 中。此时,我们找到的没有重复字符的最长子字符串将会以索引 i 开头。如果我们对所有的 i 这样做,就可以得到答案。
1 public class Solution { 2 public int lengthOfLongestSubstring(String s) { 3 int n = s.length(); 4 Set<Character> set = new HashSet<>(); 5 int ans = 0, i = 0, j = 0; 6 while (i < n && j < n) { 7 // try to extend the range [i, j] 8 if (!set.contains(s.charAt(j))){ 9 set.add(s.charAt(j++)); 10 ans = Math.max(ans, j - i); 11 } 12 else { 13 set.remove(s.charAt(i++)); 14 } 15 } 16 return ans; 17 } 18 }
优化滑动窗口
1 public class Solution { 2 public int lengthOfLongestSubstring(String s) { 3 int n = s.length(), ans = 0; 4 Map<Character, Integer> map = new HashMap<>(); // current index of character 5 // try to extend the range [i, j] 6 for (int j = 0, i = 0; j < n; j++) { 7 if (map.containsKey(s.charAt(j))) { 8 i = Math.max(map.get(s.charAt(j)), i); 9 } 10 ans = Math.max(ans, j - i + 1); 11 map.put(s.charAt(j), j + 1); 12 } 13 return ans; 14 } 15 }
执行用时最短解法
class Solution { public int lengthOfLongestSubstring(String s) { if (s ==null || s.length() <1) return 0; int ret =0; char[] sAry = s.toCharArray(); int[] pos = new int[256]; for (int i=0, j=0; j <sAry.length; j++){ i = Math.max(pos[sAry[j]] , i); ret = Math.max(ret, j-i+1); pos[sAry[j]] = j+1; } return ret; } }
Practice 4
题目描述
给定两个大小为 m 和 n 的有序数组 nums1 和 nums2 。
请找出这两个有序数组的中位数。要求算法的时间复杂度为 O(log (m+n)) 。
我的解答 执行时间208ms
1 class Solution { 2 public double findMedianSortedArrays(int[] nums1, int[] nums2) { 3 int[] array=twoToOne(nums1,nums2); 4 int n = array.length; 5 if(n%2==1){ 6 return array[n/2]; 7 }else{ 8 return ((double)array[n/2-1]+(double)array[n/2])/2; 9 } 10 11 } 12 13 public int[] twoToOne(int[] nums1,int[] nums2){ 14 int m = nums1.length; 15 int n=nums2.length; 16 int[] array=new int[m+n]; 17 int k=0; 18 for(int i=0;i<m;i++){ 19 array[k++]=nums1[i]; 20 } 21 for(int j=0;j<n;j++){ 22 array[k++]=nums2[j]; 23 } 24 25 return sort(array); 26 27 } 28 29 public int[] sort(int[] array){ 30 int[] ary = array; 31 int n = ary.length; 32 for(int i = 0;i<n;i++){ 33 for(int j=1;j<n-i;j++){ 34 if(ary[i]>ary[i+j]){ 35 int tmp = ary[i+j]; 36 ary[i+j]=ary[i]; 37 ary[i]=tmp; 38 39 } 40 } 41 } 42 return ary; 43 } 44 }
答案解析
然而答案并没有弄懂
1 class Solution { 2 public double findMedianSortedArrays(int[] A, int[] B) { 3 int m = A.length; 4 int n = B.length; 5 if (m > n) { // to ensure m<=n 6 int[] temp = A; A = B; B = temp; 7 int tmp = m; m = n; n = tmp; 8 } 9 int iMin = 0, iMax = m, halfLen = (m + n + 1) / 2; 10 while (iMin <= iMax) { 11 int i = (iMin + iMax) / 2; 12 int j = halfLen - i; 13 if (i < iMax && B[j-1] > A[i]){ 14 iMin = iMin + 1; // i is too small 15 } 16 else if (i > iMin && A[i-1] > B[j]) { 17 iMax = iMax - 1; // i is too big 18 } 19 else { // i is perfect 20 int maxLeft = 0; 21 if (i == 0) { maxLeft = B[j-1]; } 22 else if (j == 0) { maxLeft = A[i-1]; } 23 else { maxLeft = Math.max(A[i-1], B[j-1]); } 24 if ( (m + n) % 2 == 1 ) { return maxLeft; } 25 26 int minRight = 0; 27 if (i == m) { minRight = B[j]; } 28 else if (j == n) { minRight = A[i]; } 29 else { minRight = Math.min(B[j], A[i]); } 30 31 return (maxLeft + minRight) / 2.0; 32 } 33 } 34 return 0.0; 35 } 36 }
执行时间为38ms的代码范例
1 class Solution { 2 public double findMedianSortedArrays(int[] nums1, int[] nums2) { 3 4 int n = nums1.length; 5 int m = nums2.length; 6 double re = 0; 7 int t1=0; 8 int t2=0; 9 int p1=0; 10 int p2=0; 11 if((n+m)%2 == 1){ 12 for(int i = 0; i< (n+m)/2 + 1; i++){ 13 if(p1<n && p2<m){ 14 if(nums1[p1] > nums2[p2]){ 15 t1 = nums2[p2]; 16 p2++; 17 }else { 18 t1 = nums1[p1]; 19 p1++; 20 } 21 } 22 else if(p1<n ){ 23 t1 = nums1[p1]; 24 p1++; 25 } 26 else if(p2<m ){ 27 t1 = nums2[p2]; 28 p2++; 29 } 30 } 31 return t1*1.0; 32 } 33 else { 34 for(int i = 0; i< (n+m)/2; i++){ 35 if(p1<n && p2<m){ 36 if(nums1[p1] > nums2[p2]){ 37 t1 = nums2[p2]; 38 p2++; 39 }else { 40 t1 = nums1[p1]; 41 p1++; 42 } 43 } 44 else if(p1<n ){ 45 t1 = nums1[p1]; 46 p1++; 47 } 48 else if(p2<m ){ 49 t1 = nums2[p2]; 50 p2++; 51 } 52 } 53 if(p1<n && p2<m){ 54 if(nums1[p1] > nums2[p2]){ 55 t2 = nums2[p2]; 56 p2++; 57 }else { 58 t2 = nums1[p1]; 59 p1++; 60 } 61 } 62 else if(p1<n ){ 63 t2 = nums1[p1]; 64 p1++; 65 } 66 else if(p2<m ){ 67 t2 = nums2[p2]; 68 p2++; 69 } 70 return (t1+t2)/2.0; 71 72 } 73 74 75 } 76 }
Practice 5
题目描述
给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为1000。
我的解答:
1 class Solution { 2 public String longestPalindrome(String s) { 3 //find all sub string 4 String result=null; 5 if(s==""){ 6 return "can not be empty."; 7 } 8 9 char[] str = s.toCharArray(); 10 int n = str.length; 11 if(n==1){ 12 return s; 13 } 14 int len = 1; 15 for(int i=0;i<n;i++){ 16 StringBuilder sBuilder = new StringBuilder(); 17 sBuilder.append(str[i]); 18 19 for(int j=i+1;j<n;j++){ 20 sBuilder.append(str[j]); 21 String tmp =sBuilder.toString(); 22 if(isPalindrome(tmp)){ 23 if(tmp.length()>=len){ 24 len = tmp.length(); 25 result=tmp; 26 } 27 } 28 } 29 } 30 31 if(result==null){ 32 return String.valueOf(str[0]); 33 }else{ 34 return result; 35 } 36 } 37 38 public boolean isPalindrome(String s){ 39 char[] str= s.toCharArray(); 40 int n = str.length; 41 for(int i=0;i<n/2;i++){ 42 if(str[i]!=str[n-i-1]){ 43 return false; 44 } 45 } 46 return true; 47 } 48 }
提交后测试用例通过79个,第80个超出时间限制。
答案解析:
中心扩展算法
回文中心的两侧互为镜像。因此,回文可以从它的中心展开,并且只有 2n - 1 个这样的中心。
你可能会问,为什么会是 2n - 1 个,而不是 nn 个中心?原因在于所含字母数为偶数的回文的中心可以处于两字母之间。
例如“abba”的中心在两个‘b’之间。
1 public String longestPalindrome(String s) { 2 int start = 0, end = 0; 3 for (int i = 0; i < s.length(); i++) { 4 int len1 = expandAroundCenter(s, i, i); 5 int len2 = expandAroundCenter(s, i, i + 1); 6 int len = Math.max(len1, len2); 7 if (len > end - start) { 8 start = i - (len - 1) / 2; 9 end = i + len / 2; 10 } 11 } 12 return s.substring(start, end + 1); 13 } 14 15 private int expandAroundCenter(String s, int left, int right) { 16 int L = left, R = right; 17 while (L >= 0 && R < s.length() && s.charAt(L) == s.charAt(R)) { 18 L--; 19 R++; 20 } 21 return R - L - 1; 22 }