7.14
REVIEW
双指针dp 说真的想不到能这样dp 左dp一遍最高右遍历一遍最高
1 2 3 4 5 6 7 8 9 10
| class Solution { public int trap(int[] height) { int []dpL=new int[height.length],dpR = new int[height.length]; int ans = 0;dpL[0] = height[0];dpR[height.length-1] = height[height.length-1]; for(int i=1;i<height.length;i++) dpL[i]=Math.max(dpL[i-1],height[i]); for(int i=height.length-2;i>=0;i--) dpR[i]=Math.max(dpR[i+1],height[i]); for(int i=0;i<height.length;i++) ans+=Math.min(dpL[i],dpR[i])-height[i]; return ans; } }
|
还有更优的双指针加dp解法 因为两个dp都只用维护一个最大值 证明公式后可以用双指针dp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| class Solution { public int trap(int[] height) { int ans = 0, leftMax = height[0], rightMax=height[height.length-1], left = 0 ,right = height.length-1; while(left<=right){ leftMax = Math.max(leftMax,height[left]); rightMax = Math.max(rightMax,height[right]); if(leftMax<rightMax){ ans+=leftMax-height[left]; left++; }else{ ans+=rightMax-height[right]; right--; } } return ans; } }
|
和上题差不多的左右两次dp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| class Solution { public int candy(int[] ratings) { int []dpL=new int[ratings.length],dpR = new int[ratings.length]; int ans =0 ; dpL[0] = 1;dpR[ratings.length-1]=1; for(int i=1;i<ratings.length;i++){ if(ratings[i]>ratings[i-1]) dpL[i] = dpL[i-1]+1; else dpL[i]=1; } for(int i=ratings.length-2;i>=0;i--){ if(ratings[i]>ratings[i+1]) dpR[i] = dpR[i+1]+1; else dpR[i]=1; } for(int i=0;i<ratings.length;i++){ ans += Math.max(dpR[i],dpL[i]); } return ans; } }
|
第一次做单调栈 执行时间有点惨哦 227ms
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| class Solution { public int[] dailyTemperatures(int[] temperatures) { Stack<Integer> index = new Stack<>(),value = new Stack<>(); int []ans = new int[temperatures.length]; for(int i=0;i<temperatures.length;i++){ while(!value.empty()&&temperatures[i]>value.peek()){ int t_index = index.pop(); ans[t_index] = i-t_index; value.pop(); } value.push(temperatures[i]); index.push(i); } return ans; } }
|
稍微改了一下 用了一个数组栈 168ms
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| class Solution { public int[] dailyTemperatures(int[] temperatures) { Stack<int[]> index = new Stack<>(); int []ans = new int[temperatures.length]; for(int i=0;i<temperatures.length;i++){ while(!index.empty()&&temperatures[i]>index.peek()[0]){ int[] t_index = index.pop(); ans[t_index[1]] = i-t_index[1]; } index.push(new int[]{temperatures[i],i}); } return ans; } }
|
哦牛皮 原来别人比我快了将近7倍只是因为他们用了Deque是吧 那是真的牛皮 23ms
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| class Solution { public int[] dailyTemperatures(int[] temperatures) { Deque<int[]> index = new ArrayDeque<>(); int []ans = new int[temperatures.length]; for(int i=0;i<temperatures.length;i++){ while(!index.isEmpty()&&temperatures[i]>index.peek()[0]){ int[] t_index = index.pop(); ans[t_index[1]] = i-t_index[1]; } index.push(new int[]{temperatures[i],i}); } return ans; } }
|
7.15
1 2 3 4 5 6 7 8 9 10 11 12 13
| class Solution { public String mergeAlternately(String word1, String word2) { StringBuilder ans = new StringBuilder(); int len1 = word1.length(),len2 = word2.length(); for(int i=0;i<Math.min(len1,len2);i++){ ans.append(word1.charAt(i)); ans.append(word2.charAt(i)); } if(len1<len2) ans.append(word2.substring(len1)); else if(len2<len1) ans.append(word1.substring(len2)); return ans.toString(); } }
|
REVIEW
这是简单题?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| class Solution { public String gcdOfStrings(String str1, String str2) { int len1 = str1.length(),len2 = str2.length(); for(int i=Math.min(len1,len2);i>=1;i--){ if(len1%i==0&&len2%i==0){ String s = str1.substring(0,i); if(check(str1,s)&&check(str2,s)) return s; } } return ""; } public boolean check(String s1,String s2){ int len = s1.length()/s2.length(); return s2.repeat(len).equals(s1); } }
|
辗转相除法(gcd)优化 数学证明
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| class Solution { public String gcdOfStrings(String str1, String str2) { if (!str1.concat(str2).equals(str2.concat(str1))) { return ""; } return str1.substring(0, gcd(str1.length(), str2.length())); }
public int gcd(int a, int b) { int remainder = a % b; while (remainder != 0) { a = b; b = remainder; remainder = a % b; } return b; } }
|
三目运算符好像比Math.max快?
1 2 3 4 5 6 7 8 9
| class Solution { public List<Boolean> kidsWithCandies(int[] candies, int extraCandies) { List<Boolean> ans = new ArrayList<>(); int max = -1; for(int candy:candies) max = max>candy?max:candy; for(int candy:candies) ans.add(candy+extraCandies>=max); return ans; } }
|
要注意边界条件的处理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| class Solution { public boolean canPlaceFlowers(int[] flowerbed, int n) { if(n==0) return true; if(flowerbed.length==1) return flowerbed[0]!=1; int ans = 0; if(flowerbed[0]==0&&flowerbed[1]==0) flowerbed[0]=-1; for(int i=1;i<flowerbed.length;i++){ if(flowerbed[i]==0){ if(flowerbed[i-1]==-1) { ans++; if(ans>=n) return true; } else if (flowerbed[i-1]==0) flowerbed[i]=-1; } } if(flowerbed[flowerbed.length-1]==-1) ans++; return ans>=n; } }
|
又一次提醒我用set和hashmap会有多慢
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| class Solution { public String reverseVowels(String s) { int [] indexes = new int[s.length()]; int index = 0; StringBuilder chars = new StringBuilder(s); for(int i=0;i<s.length();i++) if(isVowel(chars.charAt(i))){ indexes[index] = i; index++; } char ch; for(int i=0;i<index/2;i++){ ch = chars.charAt(indexes[i]); chars.setCharAt(indexes[i],chars.charAt(indexes[index-i-1])); chars.setCharAt(indexes[index-i-1],ch); } return chars.toString(); } private boolean isVowel(char ch) { return ch == 'a' || ch == 'e' || ch == 'i' || ch == 'o' || ch == 'u' || ch == 'A' || ch == 'E' || ch == 'I' || ch == 'O' || ch == 'U'; } }
|
哎 我想了一下用双指针应该更快点
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| class Solution { public String reverseVowels(String s) { char [] chars = s.toCharArray(); int l=0,r = s.length()-1; while(l<r){ boolean flag1 = isVowel(chars[l]),flag2 = isVowel(chars[r]); if(flag1&&flag2){ swap(chars,l,r);l++;r--; }else if(flag1) r--; else if (flag2) l++; else {r--;l++;} } return String.valueOf(chars); } private boolean isVowel(char ch) { return ch == 'a' || ch == 'e' || ch == 'i' || ch == 'o' || ch == 'u' || ch == 'A' || ch == 'E' || ch == 'I' || ch == 'O' || ch == 'U'; } private void swap(char[] cs, int l, int r) { char c = cs[l]; cs[l] = cs[r]; cs[r] = c; } }
|
3ms -> 2ms
我想的是记录最大最小值, 结果普通地记录最小次小值就好了…
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
| class Solution { public boolean increasingTriplet(int[] nums) { int []dpL=new int[nums.length],dpR= new int[nums.length]; int min = Integer.MAX_VALUE,max = Integer.MIN_VALUE; for(int i=0;i<nums.length;i++) { min = Math.min(nums[i], min); dpL[i] = min; } for(int i=nums.length-1;i>=0;i--) { max = Math.max(nums[i], max); dpR[i] = max; if(nums[i]>dpL[i]&&nums[i]<dpR[i]) return true; } return false; } }
class Solution { public boolean increasingTriplet(int[] nums) { int min = nums[0],bigMin = Integer.MAX_VALUE; for(int num:nums){ if(num>min&&num<bigMin) bigMin=num; else if(min>num) min = num; else if(num>bigMin) return true; } return false; } }
|
这种题除了各种条件判断写着烦没别的了 一点乐趣也没有
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
| class Solution { public int compress(char[] chars) { int fast = 0,slow = fast,ansLen=0; while(fast<chars.length){ int len = 1; char ch = chars[fast++]; while(fast<chars.length&&ch==chars[fast]){ fast++;len++; } if(len==1){ chars[slow++]=ch;ansLen++; }else if(len<10){ chars[slow++]=ch;chars[slow++]= (char) (len+'0');ansLen+=2; }else{ chars[slow++]=ch;ansLen++; String str = String.valueOf(len); char [] cLen = str.toCharArray(); for(char c:cLen){ chars[slow++]=c;ansLen++; } } } return ansLen; } }
|
7.17
快排加双指针
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| class Solution { public int maxOperations(int[] nums, int k) { Arrays.sort(nums); int ans = 0, l = 0, r = nums.length-1; while(l<r){ if(nums[l]+nums[r]==k) { ans++;++l;--r; }else if(nums[l]+nums[r]<k){ ++l; }else{ --r; } } return ans; } }
|
改了一下快了2ms 据我分析应该是因为不等于k的情况比等于k的情况多很多 所以每次循环少了不少判断 还有用num记录nums[l]+nums[r] 这样就只用计算一次相加
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| class Solution { public int maxOperations(int[] nums, int k) { Arrays.sort(nums); int ans = 0, l = 0, r = nums.length-1; while(l<r){ int num = nums[l]+nums[r]; if(num<k) { ++l; }else if(num>k){ --r; }else{ ans++;++l;--r; } } return ans; } }
|
第一次提交的时候看错题了( ̄_ ̄|||)
先计算前k个字符串然后dp ans等于k时就返回结果减少计算量
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| class Solution { public int maxVowels(String s, int k) { int []dp = new int[s.length()]; char [] chars = s.toCharArray(); int ans = 0, len = s.length(); dp[0] = isTarget(chars[0])?1:0; for(int i=1;i<k;i++){ dp[i]= isTarget(chars[i])?dp[i-1]+1:dp[i-1]; }ans = Math.max(ans,dp[k-1]); if(ans==k)return k; for(int i=k;i<len;i++){ int num = dp[i-1]- (isTarget(chars[i-k])?1:0); dp[i]= isTarget(chars[i])?num +1:num; ans = Math.max(ans,dp[i]); if(ans==k)return k; } return ans; }
private boolean isTarget(char ch){ return ch=='a'||ch=='e'||ch=='i'||ch=='o'||ch=='u'; } }
|
看别人的代码又学到一招 真是为了优化无所不用其极啊 用数组存储元音字母 判断速度更快 11ms -> 5ms
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
| class Solution { public static final int[] cnt = new int[128]; static{ Arrays.fill(cnt,0); cnt['a'] = 1; cnt['e'] = 1; cnt['i'] = 1; cnt['o'] = 1; cnt['u'] = 1; } public int maxVowels(String s, int k) { int []dp = new int[s.length()]; char [] chars = s.toCharArray(); int ans = 0, len = s.length(); dp[0] = cnt[chars[0]]; for(int i=1;i<k;i++){ dp[i]= dp[i-1]+cnt[chars[i]]; }ans = Math.max(ans,dp[k-1]); if(ans==k)return k; for(int i=k;i<len;i++){ int num = dp[i-1]- cnt[chars[i-k]]; dp[i]= num + cnt[chars[i]]; ans = Math.max(ans,dp[i]); if(ans==k)return k; } return ans; } }
|
再进一步! 因为这个dp只用记录最大值 所以可以用一个滑动窗口的最大值代替dp数组 dp 不需要了 5ms -> 4ms
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| class Solution { public int maxVowels(String s, int k) { int []cnt = new int[128]; cnt['a'] = 1; cnt['e'] = 1; cnt['i'] = 1; cnt['o'] = 1; cnt['u'] = 1; char [] chars = s.toCharArray(); int ans = 0, len = s.length(); ans += cnt[chars[0]]; for(int i=1;i<k;i++){ ans += cnt[chars[i]]; } if(ans==k)return k; int sum = ans; for(int i=k;i<len;i++){ sum += - cnt[chars[i-k]] + cnt[chars[i]]; ans = Math.max(ans,sum); if(ans==k)return k; } return ans; } }
|
和上题差不多的滑动窗口 简单但是优化空间似乎很大?
1 2 3 4 5 6 7 8 9 10 11 12 13
| class Solution { public double findMaxAverage(int[] nums, int k) { double ans , sum = 0; for(int i=0;i<k;i++) sum += nums[i]; ans = sum/k; for(int i=k;i<nums.length;i++){ sum += -nums[i-k] + nums[i]; ans = Math.max(ans,sum/k); } return ans; } }
|
哦 阿西吧 没必要更新最大值的时候算平均数的 最后把最大和除一下就行 5ms->2ms
1 2 3 4 5 6 7 8 9 10 11 12 13
| class Solution { public double findMaxAverage(int[] nums, int k) { int ans,sum = 0,len = nums.length; for(int i=0;i<k;i++) sum += nums[i]; ans = sum/k; for(int i=k;i<len;i++){ sum += -nums[i-k] + nums[i]; ans = Math.max(ans,sum); } return (double) ans /k; } }
|
7.18
REVIEW
之前没写过这种滑动窗口长度可变的题 一开始写的时候用定长滑动窗口一直写不出来 看了题解发现其实很简单
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| class Solution { public int longestOnes(int[] nums, int k) { int len=nums.length,zero = 0,sum=0,ans=0,l=0; for(int r=0;r<len;r++){ zero+=nums[r]==0?1:0; sum+=nums[r]; while(zero>k){ l++;zero-=nums[l]==0?1:0;sum-=nums[l]; } ans=Math.max(ans,zero+sum); } return ans; } }
|
跟上题思路差不多的可变滑动窗口
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| class Solution { public int longestSubarray(int[] nums) { int len=nums.length,zero = 0,sum=0,ans=0,l=0; for(int r=0;r<len;r++){ zero+=nums[r]==0?1:0; sum+=nums[r]; while(zero>1){ zero-=nums[l]==0?1:0;sum-=nums[l];l++; } ans=Math.max(ans,sum+zero-1); } return ans; } }
|
优化: 不需要维护sum 三元运算符换成if判断更快
1 2 3 4 5 6 7 8 9 10 11 12 13
| class Solution { public int longestSubarray(int[] nums) { int len=nums.length,zero = 0,ans=0,l=0; for(int r=0;r<len;r++){ if(nums[r]==0) ++zero; while(zero>1){ if(nums[l++]==0) --zero; } ans=Math.max(ans,r-l); } return ans; } }
|
1 2 3 4 5 6 7 8 9 10 11
| class Solution { public int largestAltitude(int[] gain) { int len = gain.length,ans=0,h=0; for(int i=1;i<=len;i++){ h+=gain[i-1]; ans=Math.max(ans,h); } return ans; } }
|
7.19
维护一个前缀和一个后缀和 三次遍历 应该还有挺大优化空间的
1 2 3 4 5 6 7 8 9 10
| class Solution { public int pivotIndex(int[] nums) { int len = nums.length; int []left = new int[len],right = new int[len]; for(int i=1;i<len;i++) left[i]=left[i-1]+nums[i-1]; for(int i=len-2;i>=0;i--) right[i]=right[i+1]+nums[i+1]; for(int i=0;i<len;i++) if(left[i]==right[i])return i; return -1; } }
|
原来如此 计算数组总和就行了 维护前后缀和是在计算复杂的时候(比如乘除之类的)才用
1 2 3 4 5 6 7 8 9 10 11
| class Solution { public int pivotIndex(int[] nums) { int sum = 0,curSum=0; for(int num:nums) sum+=num; for(int i=0;i<nums.length;i++){ curSum+=nums[i]; if(sum-curSum==curSum-nums[i]) return i; } return -1; } }
|
用了两个set 本来以为时间会很烂…结果击败了79.5% 其实还好…?
1 2 3 4 5 6 7 8 9 10 11 12
| class Solution { public boolean uniqueOccurrences(int[] arr) { int [] nums = new int[2001]; Set<Integer> set1 = new HashSet<>(),set2=new HashSet<>(); for(int num:arr){++nums[num+1000];set1.add(num);} for(Integer num:set1){ if(set2.contains(nums[num+1000])) return false; set2.add(nums[num+1000]); } return true; } }
|
本来用了三个数组三次遍历以为时间会被暴打了 结果击败100%…?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| class Solution { public List<List<Integer>> findDifference(int[] nums1, int[] nums2) { List<List<Integer>> ans = new ArrayList<>(); List<Integer> n1 = new ArrayList<>(),n2 = new ArrayList<>(); ans.add(n1);ans.add(n2); boolean []set1 = new boolean[2001], set2 = new boolean[2001], set3 = new boolean[2001]; for(int num:nums1) set1[num+1000] = true; for(int num:nums2){ int n = num+1000; if(!set1[n]&&!set2[n]) n2.add(num); set2[n] = true; } for(int num:nums1){ int n = num+1000; if(!set2[n]&&!set3[n]) n1.add(num); set3[n]=true; } return ans; } }
|
7.20
REVIEW
还以为中等题会这么简单呢…一千多ms
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| class Solution { public String removeStars(String s) { StringBuilder stringBuilder = new StringBuilder(s); int index=0; while(index<stringBuilder.length()){ if(stringBuilder.charAt(index)=='*'){ stringBuilder.delete(index-1,index+1); --index; }else{ index++; } } return stringBuilder.toString(); } }
|
还是有点麻烦的 从后往前遍历会简单很多 碰到星号就维护一个星号数量 星号数量大于0时就遍历下去直到星号数量等于0 (12ms defeat 94%)
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
| class Solution { public String removeStars(String s) { char[] chars = s.toCharArray(); int len=s.length(),ansLen=len,ansIndex=0; for(int i=len-1;i>=0;){ if(chars[i]=='*'){ int index=1,star=1;--i; while(star>0){ if(chars[i]!='*'){ --star;chars[i]='*'; }else{ ++star; }i--;++index; }ansLen-=index; }else i--; } char [] ans = new char[ansLen]; for(int i=0;i<len;i++){ if(chars[i]!='*'){ ans[ansIndex++]=chars[i]; } } return String.valueOf(ans); } }
|
我去 居然还有这种简单的写法 虽然时间不如上面的写法但是真的简单啊 效率的选择
因为是设置长度所以不用删除 耗时减少了很多 22ms
1 2 3 4 5 6 7 8 9 10
| class Solution { public String removeStars(String s) { StringBuilder sb=new StringBuilder(); for(char c: s.toCharArray()){ if(c=='*') sb.setLength(sb.length() - 1); else sb.append(c); } return sb.toString(); } }
|
原来这题的标签是栈… 没想到栈的解法 是我的问题
写出来就知道会慢了 34.47%其实还行
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| class Solution { public int equalPairs(int[][] grid) { Map<String, Integer> mapR = new HashMap<>(); int n=grid.length,ans=0; for (int[] R : grid) { String str = Arrays.toString(R); mapR.put(str,mapR.getOrDefault(str, 0)+1); } for(int i=0;i<n;i++){ int [] L = new int[n]; for (int k=0;k<n;k++) L[k]=grid[k][i]; String str = Arrays.toString(L); ans+= mapR.getOrDefault(str, 0); } return ans; } }
|
也不知道是为什么 用了List之后快了将近一倍 18ms
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| class Solution { public int equalPairs(int[][] grid) { Map<List<Integer>, Integer> mapR = new HashMap<>(); int n=grid.length,ans=0; for (int[] R : grid) { List<Integer> list = new ArrayList<>(); for(int num:R) list.add(num); mapR.put(list,mapR.getOrDefault(list, 0)+1); } for(int i=0;i<n;i++){ List<Integer> list = new ArrayList<>(); for (int k=0;k<n;k++) list.add(grid[k][i]); ans+= mapR.getOrDefault(list, 0); } return ans; } }
|
看到一个妙解 转置矩阵之后对比每行 10ms
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| class Solution {
public int equalPairs(int[][] grid) { int n = grid.length; int[][] arr = new int[n][n]; int count = 0; for(int i=0;i<n;i++){ for(int j=0;j<n;j++){ arr[i][j] = grid[j][i]; } } for(int i=0;i<n;i++){ for(int j=0;j<n;j++){ if(Arrays.equals(grid[i],arr[j])){ count++; } } } return count; } }
|
80.44% 还行 就是代码有点臃肿了
记录字符出现次数的次数 还要注意两个word的字符种类是相同的 只要每种字符出现的次数能跟另一个word一一对应就行
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| class Solution { public boolean closeStrings(String word1, String word2) { if(word1.length()!=word2.length()) return false; Map<Integer,Integer> map1 = new HashMap<>(),map2 = new HashMap<>(); int []nums1 = new int[26],nums2=new int[26]; char [] chars1 = word1.toCharArray(),chars2 = word2.toCharArray(); for(int i=0;i<word1.length();i++){ ++nums1[chars1[i]-'a'];++nums2[chars2[i]-'a']; }for(int i=0;i<26;i++){ if((nums1[i]==0&&nums2[i]!=0)||(nums2[i]==0&&nums1[i]!=0)) return false; if(nums1[i]!=0){ map1.put(nums1[i],map1.getOrDefault(nums1[i],0)+1); map2.put(nums2[i],map2.getOrDefault(nums2[i],0)+1); } } for(Integer num:map1.keySet()){ if(!map2.containsKey(num)|| !Objects.equals(map1.get(num), map2.get(num))) return false; } return true; } }
|