力扣算法题——这里都是自己做过的,打算从2025年8月开始能保持在一天一道的频率。力扣热门100题进行了标注。我看热门题里面二叉树和动态规划是不太熟的,要抽时间花功夫学习一下。
哈希
给定一个整数数组 nums
和一个整数目标值 target
,请你在该数组中找出 和为目标值 target
的那 两个 整数,并返回它们的数组下标。
题解:用hash值中的containskey方法,遍历一遍数组,存在和target-num1一样大的数字num2,代表num1+num2=target,value记录下标。
1 2 3 4 5 6 7 8 9 10 11 12 13 class Solution { public int [] twoSum(int [] nums, int target) { HashMap<Integer,Integer> map = new HashMap <Integer,Integer>(); int len = nums.length; for (int i=0 ;i<len;i++){ if (map.containsKey(target-nums[i])){ return new int []{map.get(target-nums[i]),i}; } map.put(nums[i],i); } return new int []{0 }; } }
题解:遍历子串数组,全部按acsill码排序。排好序向map中添加,存在就列表添加,不存在创建key,打印value
给你一个字符串数组,请你将 字母异位词 组合在一起。可以按任意顺序返回结果列表。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 class Solution { public List<List<String>> groupAnagrams (String[] strs) { HashMap<String, List<String>> map = new HashMap <>(); for (String str : strs) { char [] chars = str.toCharArray(); Arrays.sort(chars); String key = new String (chars); List<String> listRes = map.getOrDefault(key, new ArrayList <>()); listRes.add(str); map.put(key,listRes); } return new ArrayList <>(map.values()); } }
题解:先将所有数字放hashset中,存在遍历set,存在当前数字小1的中断当前循环。这样能最小开始算,当有比当前数字大1的while循环,一直+1,直到不存在,记录长度。这样就能找到最长连续的整数长度。
给定一个未排序的整数数组 nums
,找出数字连续的最长序列(不要求序列元素在原数组中连续)的长度。
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 longestConsecutive (int [] nums) { int length = nums.length; if (length<=1 ) return length; Set<Integer> numSet = new HashSet <>(); for (int num : nums) { numSet.add(num); } int longestStreak=0 ; int currentStreak=1 ; for (int num : numSet){ if (numSet.contains(num-1 )){ continue ; } int currentNum = num; currentStreak=1 ; while (numSet.contains(currentNum+1 )){ currentNum++; currentStreak++; } longestStreak = Math.max(longestStreak, currentStreak); } return longestStreak; } }
双指针
题解:把遍历的所有非零数给新数组,两个数组一样长,新数组没赋值的后面全0
给定一个数组 nums
,编写一个函数将所有 0
移动到数组的末尾,同时保持非零元素的相对顺序。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 class Solution { public void moveZeroes (int [] nums) { if (nums==null ) { return ; } int j = 0 ; for (int i=0 ;i<nums.length;++i) { if (nums[i]!=0 ) { nums[j++] = nums[i]; } } for (int i=j;i<nums.length;++i) { nums[i] = 0 ; } } }
题解:左右指针,一个在最左边一个在最右边,当左边高度比右边小,建立临时变量为当前左侧长度,一直左指针右移,直到大于外循环左侧长度统计最大值。同理当右侧小,右侧向左边移。为什么可以这样移动?因为只要某一侧移动的时候,遇到的柱子比之前短,就一定代表存储量小,底短了高也短了。
给定一个长度为 n
的整数数组 height
。有 n
条垂线,第 i
条线的两个端点是 (i, 0)
和 (i, height[i])
。找出其中的两条线,使得它们与 x
轴共同构成的容器可以容纳最多的水。返回容器可以储存的最大水量。
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 maxArea (int [] height) { int left = 0 ; int right = height.length-1 ; int maxArea = (right-left)*Math.min(height[left], height[right]); while (left<right) { if (height[left]<=height[right]) { int temp = height[left]; while (left<right && height[left]<=temp) { left++; } }else { int temp = height[right]; while (left<right && height[right]<=temp) { right--; } } maxArea = Math.max(maxArea, (right-left)*Math.min(height[left], height[right])); } return maxArea; } }
题解:找到三个数相加为0,先排序,从左向右遍历,同时设置左右指针,左指针是当前索引+1,右指针是右侧,判断内缩,大于0右收缩,小于0左收缩。为0就收集并且去重左右指针移动,去除重复值。
给你一个整数数组 nums
,判断是否存在三元组 [nums[i], nums[j], nums[k]]
满足 i != j
、i != k
且 j != k
,同时还满足 nums[i] + nums[j] + nums[k] == 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 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 import java.util.AbstractList;class Solution { public List<List<Integer>> threeSum (int [] nums) { return new AbstractList <List<Integer>>() { @Override public List<Integer> get (int index) { init(); return result.get(index); } @Override public int size () { init(); return result.size(); } private List<List<Integer>> result; private void init () { if (result != null ) return ; result = new ArrayList <>(); if (nums.length < 3 ) { return ; } Arrays.sort(nums); if (nums[0 ] >0 ) return ; for (int i = 0 ; i < nums.length - 2 ; i++) { int left = i + 1 ; int right = nums.length - 1 ; while (left < right) { long sum = (long ) nums[i] + nums[left] + nums[right]; if (sum == 0 ) { result.add(Arrays.asList(nums[i], nums[left], nums[right])); while (left < right && nums[left] == nums[++left]); while (left < right && nums[right] == nums[--right]); } else if (sum < 0 ) { while (left < right && nums[left] == nums[++left]); } else { while (left < right && nums[right] == nums[--right]); } } while (i < nums.length - 2 && nums[i] == nums[i + 1 ]) { i++; } } } }; } }
题解:
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 class Solution { public int trap (int [] height) { if (height.length<=2 ) return 0 ; int maxHeight = 0 ; int maxIndex = 0 ; for (int i = 0 ; i < height.length; i++) { if (height[i]>maxHeight){ maxHeight = height[i]; maxIndex=i; } } int res = 0 ; int maxTemp=0 ; int i=0 ; while (i<maxIndex){ if (height[i]>maxTemp) maxTemp=height[i]; res += maxTemp - height[i]; i++; } int j=height.length-1 ; maxTemp=0 ; while (j>maxIndex){ if (height[j]>maxTemp) maxTemp=height[j]; res += maxTemp - height[j]; j--; } return res; } }
滑动窗口
题解:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 class Solution { public int lengthOfLongestSubstring (String s) { int n = s.length(); if (s.length() <= 1 ) return n; char [] occ = new char [128 ]; char [] chars = s.toCharArray(); int maxRes = 0 ; for (int left = 0 ,right=0 ; right < n; right++) { char c = chars[right]; occ[c]++; while (occ[c]>1 ){ occ[chars[left]]--; left++; } maxRes = Math.max(maxRes, right - left + 1 ); } return maxRes; } }
题解:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 class Solution { public List<Integer> findAnagrams (String s, String p) { List<Integer> res = new ArrayList <>(); int sLen = s.length(); int pLen = p.length(); if (sLen < pLen) return res; int [] pCount = new int [26 ]; int [] sCount = new int [26 ]; for (int i = 0 ; i < pLen; i++) pCount[p.charAt(i) - 'a' ]++; for (int i=0 ;i<sLen;i++){ sCount[s.charAt(i) - 'a' ]++; if (i>=pLen) sCount[s.charAt(i-pLen) - 'a' ]--; if (i>=pLen-1 ){ if (Arrays.equals(pCount, sCount))res.add(i-pLen+1 ); } } return res; } }
子串
题解:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 class Solution { public int subarraySum (int [] nums, int k) { int c = 0 ; int p = 0 ; Map<Integer, Integer> pc = new HashMap <>((int ) (nums.length / 0.75 ) + 1 ); pc.put(0 , 1 ); for (int num : nums) { p += num; c += pc.getOrDefault(p - k, 0 ); pc.merge(p, 1 , Integer::sum); } return c; } }
tag -——队列 数组 滑动 窗口 单调队列 堆(优先队列)
题解:用栈的思想,窗口为k位,刚开始不进while循环,当队列长度大于k以后进行操作。将队列中如果靠前的数后面有比它大的就弹出,将最大值放进res
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 [] maxSlidingWindow(int [] nums, int k) { if (k==1 || nums==null ) return nums; int len=nums.length; int [] res = new int [len-k+1 ]; LinkedList<Integer> queue = new LinkedList (); for (int i=0 ;i<len;i++){ while (!queue.isEmpty() && nums[queue.peekLast()] <= nums[i]){ queue.pollLast(); } queue.addLast(i); if (queue.peek() <= i-k){ queue.poll(); } if (i+1 >=k) res[i-k+1 ]=nums[queue.peek()]; } return res; } }
tag——哈希表 字符串 滑动窗口
题解:通过distance标志位,当右指针遍历到全部的子串,进循环看左侧,左侧减少到子串的某值统计长度,当左侧等于目标子串之一,distance减少,右指针 继续找,找到distance,左侧再收缩
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 public String minWindow (String s, String t) { int sLen = s.length(); int tLen = t.length(); if (sLen < tLen || sLen == 0 || tLen == 0 ) return "" ; char [] sCharArray = s.toCharArray(); char [] tCharArray = t.toCharArray(); int [] winFreq = new int [64 ]; int [] tFreq = new int [64 ]; int distance = 0 ; int minLen = sLen + 1 ; for (char c : tCharArray) { tFreq[c - 'A' ]++; } int left = 0 ; int right = 0 ; int begin = 0 ; while (right < sLen) { if (tFreq[sCharArray[right] - 'A' ] == 0 ) { right++; continue ; } if (winFreq[sCharArray[right] - 'A' ] < tFreq[sCharArray[right] - 'A' ]) { distance++; } winFreq[sCharArray[right] - 'A' ]++; right++; while (distance == tLen) { if (right - left < minLen) { minLen = right - left; begin = left; } if (tFreq[sCharArray[left] - 'A' ] == 0 ) { left++; continue ; } if (winFreq[sCharArray[left] - 'A' ] == tFreq[sCharArray[left] - 'A' ]) { distance--; } winFreq[sCharArray[left] - 'A' ]--; left++; } } if (minLen == sLen + 1 ) return "" ; return s.substring(begin, begin + minLen); }
普通数组
矩阵
链表
二叉树
图论
回溯
二分查找
栈
堆
贪心算法
动态规格
多维动态规划
技巧