From 6eafee1860802f828af5f7132bf6e186df2db6de Mon Sep 17 00:00:00 2001 From: markilue <745518019@qq.com> Date: Tue, 7 Mar 2023 14:36:05 +0800 Subject: [PATCH] =?UTF-8?q?leecode=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../leecode/hot100/T26_GroupAnagrams.java | 128 ++++++++++++++++++ .../leecode/hot100/T27_MaxSubArray.java | 85 ++++++++++++ .../markilue/leecode/hot100/T28_CanJump.java | 41 ++++++ .../markilue/leecode/hot100/T29_Merge.java | 84 ++++++++++++ .../leecode/hot100/T30_UniquePaths.java | 46 +++++++ 5 files changed, 384 insertions(+) create mode 100644 Leecode/src/main/java/com/markilue/leecode/hot100/T26_GroupAnagrams.java create mode 100644 Leecode/src/main/java/com/markilue/leecode/hot100/T27_MaxSubArray.java create mode 100644 Leecode/src/main/java/com/markilue/leecode/hot100/T28_CanJump.java create mode 100644 Leecode/src/main/java/com/markilue/leecode/hot100/T29_Merge.java create mode 100644 Leecode/src/main/java/com/markilue/leecode/hot100/T30_UniquePaths.java diff --git a/Leecode/src/main/java/com/markilue/leecode/hot100/T26_GroupAnagrams.java b/Leecode/src/main/java/com/markilue/leecode/hot100/T26_GroupAnagrams.java new file mode 100644 index 0000000..27c0176 --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/hot100/T26_GroupAnagrams.java @@ -0,0 +1,128 @@ +package com.markilue.leecode.hot100; + +import org.junit.Test; + +import javax.swing.event.ListDataEvent; +import java.util.*; + +/** + *@BelongsProject: Leecode + *@BelongsPackage: com.markilue.leecode.hot100 + *@Author: markilue + *@CreateTime: 2023-03-07 10:17 + *@Description: + * TODO 力扣49题 字母异位词分组: + * 给你一个字符串数组,请你将 字母异位词 组合在一起。可以按任意顺序返回结果列表。 + * 字母异位词 是由重新排列源单词的字母得到的一个新单词,所有源单词中的字母通常恰好只用一次。 + *@Version: 1.0 + */ +public class T26_GroupAnagrams { + + @Test + public void test() { + String[] str={"eat", "tea", "tan", "ate", "nat", "bat"}; +// String[] str = {""}; +// String[] str = {"ac","c"}; + System.out.println(groupAnagrams(str)); + } + + List> result = new ArrayList<>(); + List cur = new ArrayList<>(); + Map map = new HashMap<>(); + Map> bigMap=new HashMap<>(); + + //TODO 超出时间限制,第111个无法通过;修改后使用bigmap只在空的时候记录,通过 :速度击败5% 内存击败5% + public List> groupAnagrams(String[] strs) { + boolean[] used = new boolean[strs.length];//记录这个单词是否被使用过 + for (int i = 0; i < strs.length; i++) { + if (!used[i]) { + used[i] = true; + addMap(strs[i],map,i); + cur.add(strs[i]); + for (int j = i + 1; j < strs.length; j++) { + if (!used[j] && isAnagrams(strs[j],j)) { + cur.add(strs[j]); + used[j] = true; + } + } + result.add(new ArrayList<>(cur)); + cur.clear(); + map.clear(); + } + } + return result; + + } + + public void addMap(String str,Map map,int index) { + for (int i = 0; i < str.length(); i++) { + char key = str.charAt(i); + map.put(key, map.getOrDefault(key, 0) + 1); + } + bigMap.put(index, map); + } + + public boolean isAnagrams(String curStr,int index) { + Map curMap = bigMap.getOrDefault(index, new HashMap<>()); + + if(curMap.isEmpty()){ + addMap(curStr,curMap,index); + } + + return curMap.equals(map); + } + + + /** + * 官方计数法:由于互为字母异位词的两个字符串包含的字母相同, + * 因此两个字符串中的相同字母出现的次数一定是相同的 + * 故可以将每个字母出现的次数使用字符串表示,作为哈希表的键。 + * 速度击败26.63% 内存击败22.41% 10ms + * @param strs + * @return + */ + public List> groupAnagrams1(String[] strs) { + Map> map = new HashMap>(); + for (String str : strs) { + int[] counts = new int[26]; + int length = str.length(); + for (int i = 0; i < length; i++) { + counts[str.charAt(i) - 'a']++; + } + // 将每个出现次数大于 0 的字母和出现次数按顺序拼接成字符串,作为哈希表的键 + StringBuffer sb = new StringBuffer(); + for (int i = 0; i < 26; i++) { + if (counts[i] != 0) { + sb.append((char) ('a' + i)); + sb.append(counts[i]); + } + } + String key = sb.toString(); + List list = map.getOrDefault(key, new ArrayList()); + list.add(str); + map.put(key, list); + } + return new ArrayList>(map.values()); + } + + + /** + * 官方合理且最快:通过排序建立key + * 速度击败80.36% 内存击败57.98% 6ms + * @param strs + * @return + */ + public List> groupAnagrams2(String[] strs) { + Map> map = new HashMap<>(); + for (String str : strs) { + char[] cs = str.toCharArray(); + Arrays.sort(cs); + String key = String.valueOf(cs); + List list = map.getOrDefault(key, new ArrayList<>()); + list.add(str); + map.put(key, list); + } + return new ArrayList(map.values()); + } + +} diff --git a/Leecode/src/main/java/com/markilue/leecode/hot100/T27_MaxSubArray.java b/Leecode/src/main/java/com/markilue/leecode/hot100/T27_MaxSubArray.java new file mode 100644 index 0000000..5a2377a --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/hot100/T27_MaxSubArray.java @@ -0,0 +1,85 @@ +package com.markilue.leecode.hot100; + +import org.junit.Test; + +/** + *@BelongsProject: Leecode + *@BelongsPackage: com.markilue.leecode.hot100 + *@Author: markilue + *@CreateTime: 2023-03-07 11:38 + *@Description: + * TODO 力扣53题 最大子数组和: + * 给你一个整数数组 nums ,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。 + * 子数组 是数组中的一个连续部分。 + *@Version: 1.0 + */ +public class T27_MaxSubArray { + + @Test + public void test(){ + int[] nums={-2,-1}; + System.out.println(maxSubArray1(nums)); + } + + /** + * 贪心:要尽可能多的数字,如果等于0了直接抛弃 + * 速度击败100% 内存击败79.27% + * @param nums + * @return + */ + public int maxSubArray(int[] nums) { + int cur = 0; + int maxValue = Integer.MIN_VALUE; + + for (int i = 0; i < nums.length; i++) { + cur += nums[i]; + if (maxValue < cur) maxValue = cur; + if (cur < 0) cur = 0; + } + return maxValue; + } + + + /** + * 动态规划: dp定义为使用nums[0-i]的最大子数组和 + * 速度击败2.9% 内存击败5.9% 15ms + * @param nums + * @return + */ + public int maxSubArray1(int[] nums) { +// if(nums.length==0)return nums[0]; + int[][] dp = new int[nums.length][2]; + dp[0][0] = Integer.MIN_VALUE;//至少要一个 + dp[0][1] = nums[0];//至少要一个 + + for (int i = 1; i < nums.length; i++) { + + dp[i][0] = Math.max(dp[i - 1][0], dp[i-1][1]);//现在就不要,全不要 + dp[i][1] = Math.max(dp[i - 1][1] + nums[i], nums[i]);//要之前,还是不要之前 + } + + return Math.max(dp[dp.length-1][0],dp[dp.length-1][1]); + } + + + /** + * 动态规划: 滚动数组优化 + * 速度击败100% 内存击败68.67% 1ms + * @param nums + * @return + */ + public int maxSubArray2(int[] nums) { +// if(nums.length==0)return nums[0]; + + int dp0 = Integer.MIN_VALUE;//至少要一个 + int dp1 = nums[0];//至少要一个 + + for (int i = 1; i < nums.length; i++) { + + dp0 = Math.max(dp0, dp1);//现在就不要,全不要 + dp1 = Math.max(dp1 + nums[i], nums[i]);//要之前,还是不要之前 + } + + return Math.max(dp0,dp1); + } +} diff --git a/Leecode/src/main/java/com/markilue/leecode/hot100/T28_CanJump.java b/Leecode/src/main/java/com/markilue/leecode/hot100/T28_CanJump.java new file mode 100644 index 0000000..1cc0c3b --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/hot100/T28_CanJump.java @@ -0,0 +1,41 @@ +package com.markilue.leecode.hot100; + +/** + *@BelongsProject: Leecode + *@BelongsPackage: com.markilue.leecode.hot100 + *@Author: markilue + *@CreateTime: 2023-03-07 13:14 + *@Description: + * TODO 力扣55题 跳跃游戏: + * 给定一个非负整数数组 nums ,你最初位于数组的 第一个下标 。 + * 数组中的每个元素代表你在该位置可以跳跃的最大长度。 + * 判断你是否能够到达最后一个下标。 + *@Version: 1.0 + */ +public class T28_CanJump { + + /** + * 思路:贪心,记录一个能到的最大索引 + * 速度击败94.51% 内存击败97.5% 2ms + * @param nums + * @return + */ + public boolean canJump(int[] nums) { + + if(nums.length==1)return true; + + int maxIndex = 0; + int curIndex = 0; + + for (int i = 0; i < nums.length - 1 && i <= maxIndex; i++) { + curIndex = i + nums[i]; + if (curIndex > maxIndex) maxIndex = curIndex; + if (maxIndex >= nums.length - 1) return true; + + } + + return false; + + + } +} diff --git a/Leecode/src/main/java/com/markilue/leecode/hot100/T29_Merge.java b/Leecode/src/main/java/com/markilue/leecode/hot100/T29_Merge.java new file mode 100644 index 0000000..880f398 --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/hot100/T29_Merge.java @@ -0,0 +1,84 @@ +package com.markilue.leecode.hot100; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Comparator; +import java.util.List; + +/** + *@BelongsProject: Leecode + *@BelongsPackage: com.markilue.leecode.hot100 + *@Author: markilue + *@CreateTime: 2023-03-07 13:24 + *@Description: + * TODO 力扣56题 合并区间: + * 以数组 intervals 表示若干个区间的集合,其中单个区间为 intervals[i] = [starti, endi] 。 + * 请你合并所有重叠的区间,并返回 一个不重叠的区间数组,该数组需恰好覆盖输入中的所有区间 。 + *@Version: 1.0 + */ +public class T29_Merge { + + + /** + * 根据start排序,如果end a[0] != b[0] ? a[0] - b[0] : a[1] - b[1]); + List list = new ArrayList<>(); + + for (int[] interval : intervals) { + if (list.isEmpty() || list.get(list.size() - 1)[1] < interval[0]) { + list.add(interval); + } else { + int length = list.size() - 1; + int[] last = list.get(length); + last[1] = Math.max(last[1], interval[1]); + } + } + + return list.toArray(new int[0][0]); + + + } + + + /** + * 官方较快解法:6ms + * @param intervals + * @return + */ + public int[][] merge1(int[][] intervals) { + //按xstart排序 + Arrays.sort(intervals, new Comparator() { + @Override + public int compare(int[] o1, int[] o2) { + //优化 但是需要警惕超过int范围 + return o1[0] - o2[0]; + } + }); + + //寻找重叠区间,并进行合并 + int length=0;//记录新数组的长度 + int[][] result =new int[intervals.length][2]; + result[0]=intervals[0]; + int lastEnd=intervals[0][1]; + + for (int i = 1; i < intervals.length; i++) { + if(lastEnd>=intervals[i][0]){ + //重叠区间,需要合并 + lastEnd=Math.max(lastEnd,intervals[i][1]); + result[length][1]=lastEnd; + }else { + //非重叠区间,直接添加 + length++; + result[length]=intervals[i]; + lastEnd=intervals[i][1]; + } + } + //缩短至result的真实长度 + return Arrays.copyOf(result,length+1); + } +} diff --git a/Leecode/src/main/java/com/markilue/leecode/hot100/T30_UniquePaths.java b/Leecode/src/main/java/com/markilue/leecode/hot100/T30_UniquePaths.java new file mode 100644 index 0000000..33aada7 --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/hot100/T30_UniquePaths.java @@ -0,0 +1,46 @@ +package com.markilue.leecode.hot100; + +/** + *@BelongsProject: Leecode + *@BelongsPackage: com.markilue.leecode.hot100 + *@Author: markilue + *@CreateTime: 2023-03-07 13:40 + *@Description: + * TODO 力扣62题 不同路径: + * 一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。 + * 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish” )。 + * 问总共有多少条不同的路径? + *@Version: 1.0 + */ +public class T30_UniquePaths { + + /** + * 思路:动态规划法 ->当前的位置可以是上面往下走一步,也可以是左边往右边走一步 + * 速度击败100% 内存击败16.37% 0ms + * @param m + * @param n + * @return + */ + public int uniquePaths(int m, int n) { + + int[][] dp = new int[m][n]; + + for (int i = 0; i < m; i++) { + dp[i][0] = 1; + } + + for (int i = 0; i < n; i++) { + dp[0][i] = 1; + } + + for (int i = 1; i < m; i++) { + for (int j = 1; j < n; j++) { + dp[i][j] = dp[i - 1][j] + dp[i][j - 1]; + } + } + + return dp[m - 1][n - 1]; + + + } +}