From c1f04226175ab98a5ac409161da42c2bf4d40ada Mon Sep 17 00:00:00 2001 From: markilue <745518019@qq.com> Date: Wed, 28 Dec 2022 12:57:06 +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/hashtable/T06_CanConstruct.java | 88 ++++++++++ .../{ThreeSum.java => T07_ThreeSum.java} | 2 +- .../{FourSum.java => T08_FourSum.java} | 2 +- .../hashtable/second/T07_ThreeSum.java | 116 +++++++++++++ .../leecode/hashtable/second/T08_FourSum.java | 163 ++++++++++++++++++ ...erseString.java => T01_ReverseString.java} | 2 +- .../{ReverseStr.java => T02_ReverseStr.java} | 2 +- .../leecode/string/T03_ReplaceSpace.java | 77 +++++++++ .../string/second/T01_ReverseString.java | 87 ++++++++++ .../leecode/string/second/T02_ReverseStr.java | 63 +++++++ 10 files changed, 598 insertions(+), 4 deletions(-) create mode 100644 Leecode/src/main/java/com/markilue/leecode/hashtable/T06_CanConstruct.java rename Leecode/src/main/java/com/markilue/leecode/hashtable/{ThreeSum.java => T07_ThreeSum.java} (98%) rename Leecode/src/main/java/com/markilue/leecode/hashtable/{FourSum.java => T08_FourSum.java} (99%) create mode 100644 Leecode/src/main/java/com/markilue/leecode/hashtable/second/T07_ThreeSum.java create mode 100644 Leecode/src/main/java/com/markilue/leecode/hashtable/second/T08_FourSum.java rename Leecode/src/main/java/com/markilue/leecode/string/{ReverseString.java => T01_ReverseString.java} (97%) rename Leecode/src/main/java/com/markilue/leecode/string/{ReverseStr.java => T02_ReverseStr.java} (99%) create mode 100644 Leecode/src/main/java/com/markilue/leecode/string/T03_ReplaceSpace.java create mode 100644 Leecode/src/main/java/com/markilue/leecode/string/second/T01_ReverseString.java create mode 100644 Leecode/src/main/java/com/markilue/leecode/string/second/T02_ReverseStr.java diff --git a/Leecode/src/main/java/com/markilue/leecode/hashtable/T06_CanConstruct.java b/Leecode/src/main/java/com/markilue/leecode/hashtable/T06_CanConstruct.java new file mode 100644 index 0000000..4a2702c --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/hashtable/T06_CanConstruct.java @@ -0,0 +1,88 @@ +package com.markilue.leecode.hashtable; + +/** + *@BelongsProject: Leecode + *@BelongsPackage: com.markilue.leecode.hashtable + *@Author: dingjiawen + *@CreateTime: 2022-12-28 10:12 + *@Description: + * TODO 力扣383题 赎金信: + * 给你两个字符串:ransomNote 和 magazine ,判断 ransomNote 能不能由 magazine 里面的字符构成。 + * 如果可以,返回 true ;否则返回 false 。 + * magazine 中的每个字符只能在 ransomNote 中使用一次。 + *@Version: 1.0 + */ +public class T06_CanConstruct { + + /** + * 思路本质上还是和第一题同素异形类似,记录字母出现的次数,只不过允许多不允许少 + * 速度击败99.88%,内存击败76.12% + * @param ransomNote + * @param magazine + * @return + */ + public boolean canConstruct(String ransomNote, String magazine) { + char[] mChars = magazine.toCharArray(); + char[] rChars = ransomNote.toCharArray(); + + int[] map = new int[26];//数组当map用 + for (char mChar : mChars) { + map[mChar-'a']++; + } + + for (char rChar : rChars) { + map[rChar-'a']--; + } + + for (int i : map) { + if(i<0){ + return false; + } + } + return true; + } + + /** + * 思路:浅优化,判断可以在第二个for就开始 + * 速度击败99.88%,内存击败71.7% + * @param ransomNote + * @param magazine + * @return + */ + public boolean canConstruct2(String ransomNote, String magazine) { + char[] mChars = magazine.toCharArray(); + char[] rChars = ransomNote.toCharArray(); + + int[] map = new int[26];//数组当map用 + for (char mChar : mChars) { + map[mChar-'a']++; + } + + for (char rChar : rChars) { + map[rChar-'a']--; + if(map[rChar-'a']<0){ + return false; + } + } + return true; + } + + + /** + * 官方最快:记录这次找到的位置,如果下次要找相同的字符只能从这次的后面开始找 + * 时间复杂度是不是要高一些,本质上取决于indexOf的时间复杂度 + * 速度击败100%,内存击败96.44% + * @param ransomNote + * @param magazine + * @return + */ + public boolean canConstruct1(String ransomNote, String magazine) { + int[] charIndex = new int[26]; + for (char c : ransomNote.toCharArray()) { + int p = magazine.indexOf(c, charIndex[c - 'a']);//indexOf(char,fromIndex) + if(p == -1) return false; + charIndex[c - 'a'] = p + 1;//如果下次要找相同的字符只能从这次的后面开始找 + } + return true; + } +} diff --git a/Leecode/src/main/java/com/markilue/leecode/hashtable/ThreeSum.java b/Leecode/src/main/java/com/markilue/leecode/hashtable/T07_ThreeSum.java similarity index 98% rename from Leecode/src/main/java/com/markilue/leecode/hashtable/ThreeSum.java rename to Leecode/src/main/java/com/markilue/leecode/hashtable/T07_ThreeSum.java index 5dcb089..996c821 100644 --- a/Leecode/src/main/java/com/markilue/leecode/hashtable/ThreeSum.java +++ b/Leecode/src/main/java/com/markilue/leecode/hashtable/T07_ThreeSum.java @@ -17,7 +17,7 @@ import java.util.List; * 注意:答案中不可以包含重复的三元组。 * @Version: 1.0 */ -public class ThreeSum { +public class T07_ThreeSum { /** * 这道题使用哈希法的思路: diff --git a/Leecode/src/main/java/com/markilue/leecode/hashtable/FourSum.java b/Leecode/src/main/java/com/markilue/leecode/hashtable/T08_FourSum.java similarity index 99% rename from Leecode/src/main/java/com/markilue/leecode/hashtable/FourSum.java rename to Leecode/src/main/java/com/markilue/leecode/hashtable/T08_FourSum.java index 8682409..bb3c34c 100644 --- a/Leecode/src/main/java/com/markilue/leecode/hashtable/FourSum.java +++ b/Leecode/src/main/java/com/markilue/leecode/hashtable/T08_FourSum.java @@ -17,7 +17,7 @@ import java.util.*; * 你可以按 任意顺序 返回答案 。 * @Version: 1.0 */ -public class FourSum { +public class T08_FourSum { @Test public void test() { diff --git a/Leecode/src/main/java/com/markilue/leecode/hashtable/second/T07_ThreeSum.java b/Leecode/src/main/java/com/markilue/leecode/hashtable/second/T07_ThreeSum.java new file mode 100644 index 0000000..e9cb7b1 --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/hashtable/second/T07_ThreeSum.java @@ -0,0 +1,116 @@ +package com.markilue.leecode.hashtable.second; + +import org.junit.Test; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; + +/** + *@BelongsProject: Leecode + *@BelongsPackage: com.markilue.leecode.hashtable.second + *@Author: dingjiawen + *@CreateTime: 2022-12-28 10:30 + *@Description: + * TODO 二刷15题 三数之和: + * 给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != j、i != k 且 j != k , + * 同时还满足 nums[i] + nums[j] + nums[k] == 0 。请 + * 你返回所有和为 0 且不重复的三元组。 + * 注意:答案中不可以包含重复的三元组。 + *@Version: 1.0 + */ +public class T07_ThreeSum { + + @Test + public void test(){ + int[] nums = {-1, 0, 1, 2, -1, -4}; + System.out.println(threeSum(nums)); + } + + /** + * 思路:这题本质上是一个O(N^3)的一个暴力解法,考虑一层for放外面,里面用hashMap记录将复杂度变为O(N^2) + * 由于对于结果不考虑index只考虑具体的数,因此考虑先对数组进行排序 + * 速度击败47.14%,内存击败84.92% 22ms + * 增加第一个数大于0,则一定不可能了的判断以后 速度击败75.68%,内存击败80.11% 20ms + * @param nums + * @return + */ + public List> threeSum(int[] nums) { + List> result = new ArrayList<>(); + if (nums.length < 3) { + return result; + } + Arrays.sort(nums);//排序 + + for (int i = 0; i < nums.length - 2; i++) { + //第一个数大于0,则一定不可能了 + if(nums[i]>0){ + break; + } + //避免重复 + if(i>0&&nums[i]==nums[i-1]){ + continue; + } + int left = i + 1; + int right = nums.length - 1; + while (left < right) { + int sum = nums[left] + nums[right]; + if (sum > -nums[i]){ + //整体大于0 + right--; + }else if(sum<-nums[i]){ + //整体小于0 + left++; + }else { + //刚刚好 + result.add(new ArrayList<>(Arrays.asList(nums[i],nums[left],nums[right]))); + left++; + right--; + //由于不能重复三元组,所以需要多偏移 + while (left> threeSum1(int[] nums) { + List> res = new ArrayList>(); + if(nums.length < 3) return res; + Arrays.sort(nums); + for(int i=0;i 0 && nums[i] != nums[i-1])) { + int j = i+1; + int k = nums.length-1; + while(j cur = new ArrayList(); + cur.add(nums[i]); + cur.add(nums[j]); + cur.add(nums[k]); + res.add(cur); + while(j 0) k--; + else j++; + } + } + } + return res; + } +} diff --git a/Leecode/src/main/java/com/markilue/leecode/hashtable/second/T08_FourSum.java b/Leecode/src/main/java/com/markilue/leecode/hashtable/second/T08_FourSum.java new file mode 100644 index 0000000..d02d3e3 --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/hashtable/second/T08_FourSum.java @@ -0,0 +1,163 @@ +package com.markilue.leecode.hashtable.second; + +import org.junit.Test; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + *@BelongsProject: Leecode + *@BelongsPackage: com.markilue.leecode.hashtable.second + *@Author: dingjiawen + *@CreateTime: 2022-12-28 11:16 + *@Description: + * TODO 二刷力扣18题 四数之和: + * 给你一个由 n 个整数组成的数组 nums ,和一个目标值 target 。 + * 请你找出并返回满足下述全部条件且不重复的四元组 [nums[a], nums[b], nums[c], nums[d]] + * (若两个四元组元素一一对应,则认为两个四元组重复): + * 0 <= a, b, c, d < n + * a、b、c 和 d 互不相同 + * nums[a] + nums[b] + nums[c] + nums[d] == target + * 你可以按 任意顺序 返回答案 。 + *@Version: 1.0 + */ +public class T08_FourSum { + + @Test + public void test() { + int[] nums = {1, 0, -1, 0, -2, 2}; + int target = 0; + System.out.println(fourSum(nums, target)); + } + + @Test + public void test1() { + int[] nums = {2, 2, 2, 2, 2}; + int target = 8; + System.out.println(fourSum(nums, target)); + } + + @Test + public void test2() { + int[] nums = {1, -2, -5, -4, -3, 3, 3, 5}; + int target = -11; + System.out.println(fourSum(nums, target)); + } + + /** + * 思路:在三数之和外面再加上一层for,时间复杂度O(N^3) + * 熟读击败49.87%,内存击败71.72% + * @param nums + * @param target + * @return + */ + public List> fourSum(int[] nums, int target) { + List> result = new ArrayList<>(); + if (nums.length < 4) { + return result; + } + Arrays.sort(nums); + + for (int i = 0; i < nums.length - 3; i++) { + if (nums[i] > 0 && nums[i] > target) break; + if (i > 0 && nums[i] == nums[i - 1]) continue; + for (int j = i + 1; j < nums.length - 2; j++) { + if (j > i + 1 && nums[j] == nums[j - 1]) continue; + + int left = j + 1; + int right = nums.length - 1; + + while (left < right) { + long sum = (long) target - nums[left] - nums[right]; + if (sum < nums[i] + nums[j]) { + //整体大于target + right--; + } else if (sum > nums[i] + nums[j]) { + //整体小于target + left++; + } else { + //刚刚好 + result.add(new ArrayList<>(Arrays.asList(nums[i], nums[j], nums[left], nums[right]))); + left++; + right--; + while (left < right && nums[left - 1] == nums[left]) left++; + while (left < right && nums[right + 1] == nums[right]) right--; + } + } + } + } + + return result; + + } + + /** + * 官方最快:2ms + * 与本人一致,多了几个考验功力的减枝操作 + * @param nums + * @param target + * @return + */ + public List> fourSum1(int[] nums, int target) { + Arrays.sort(nums); + List> res = new ArrayList<>(); + int length = nums.length; + for (int i = 0; i < length - 3; i++) { + // 跳过重复值 + if (i > 0 && nums[i] == nums[i - 1]) { + continue; + } + // 最小合都大于目标值,说明无解 + if ((long) nums[i] + nums[i + 1] + nums[i + 2] + nums[i + 3] > target) { + //太大了 + break; + } + // 最大合小于目标值,说明i太小了,继续后移 + if ((long) nums[i] + nums[length - 3] + nums[length - 2] + nums[length - 1] < target) { + //太小了 + continue; + } + for (int j = i + 1; j < length - 2; j++) { + // 跳过重复的数字 + if (j > i + 1 && nums[j] == nums[j - 1]) { + continue; + } + // 最小合都大于目标值,说明无解 + if ((long) nums[i] + nums[j] + nums[j + 1] + nums[j + 2] > target) { + break; + } + // 最大合小于目标值,说明i太小了,继续后移 + if ((long) nums[i] + nums[j] + nums[length - 2] + nums[length - 1] < target) { + continue; + } + int left = j + 1, right = length - 1; + while (left < right) { + int x = nums[left], y = nums[right]; + int sum = nums[i] + nums[j] + x + y; + if (sum == target) { + res.add(Arrays.asList(nums[i], nums[j], x, y)); + // 将两个指针都往中间推移,遇到重复的数字就跳过 + left++; + while (left < right && nums[left] == nums[left - 1]) { + left++; + } + right--; + while (left < right && nums[right] == nums[right + 1]) { + right--; + } + } else if (sum < target) { + // 和小于目标值,因为是排序过的,要想结果变大,左标就要往右移动,数字更大 + left++; + } else { + // 同理,和大于目标值,右标就要往左移动,数字更小 + right--; + } + } + } + } + return res; + + + } +} diff --git a/Leecode/src/main/java/com/markilue/leecode/string/ReverseString.java b/Leecode/src/main/java/com/markilue/leecode/string/T01_ReverseString.java similarity index 97% rename from Leecode/src/main/java/com/markilue/leecode/string/ReverseString.java rename to Leecode/src/main/java/com/markilue/leecode/string/T01_ReverseString.java index f284b79..3e4daf1 100644 --- a/Leecode/src/main/java/com/markilue/leecode/string/ReverseString.java +++ b/Leecode/src/main/java/com/markilue/leecode/string/T01_ReverseString.java @@ -14,7 +14,7 @@ import org.junit.Test; * * @Version: 1.0 */ -public class ReverseString { +public class T01_ReverseString { @Test public void test(){ diff --git a/Leecode/src/main/java/com/markilue/leecode/string/ReverseStr.java b/Leecode/src/main/java/com/markilue/leecode/string/T02_ReverseStr.java similarity index 99% rename from Leecode/src/main/java/com/markilue/leecode/string/ReverseStr.java rename to Leecode/src/main/java/com/markilue/leecode/string/T02_ReverseStr.java index 50387ac..39dc0d1 100644 --- a/Leecode/src/main/java/com/markilue/leecode/string/ReverseStr.java +++ b/Leecode/src/main/java/com/markilue/leecode/string/T02_ReverseStr.java @@ -13,7 +13,7 @@ import org.junit.Test; * 2)如果剩余字符小于 2k 但大于或等于 k 个,则反转前 k 个字符,其余字符保持原样。 * @Version: 1.0 */ -public class ReverseStr { +public class T02_ReverseStr { @Test public void test() { diff --git a/Leecode/src/main/java/com/markilue/leecode/string/T03_ReplaceSpace.java b/Leecode/src/main/java/com/markilue/leecode/string/T03_ReplaceSpace.java new file mode 100644 index 0000000..7e0dcc4 --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/string/T03_ReplaceSpace.java @@ -0,0 +1,77 @@ +package com.markilue.leecode.string; + +import org.junit.Test; + +import java.util.Arrays; + +/** + *@BelongsProject: Leecode + *@BelongsPackage: com.markilue.leecode.string + *@Author: dingjiawen + *@CreateTime: 2022-12-28 12:41 + *@Description: + * TODO 剑指offer05 替换空格: + * + *@Version: 1.0 + */ +public class T03_ReplaceSpace { + + @Test + public void test(){ + String s = "We are happy."; + System.out.println(replaceSpace(s)); + } + + /** + * 思路:使用额外的辅助空间build进行构造 + * 速度击败100%,内存击败36.8% + * @param s + * @return + */ + public String replaceSpace(String s) { + StringBuilder builder = new StringBuilder(); + char[] chars = s.toCharArray(); + for (char aChar : chars) { + if(' '==aChar){ + builder.append("%20"); + }else { + builder.append(aChar); + } + } + + return builder.toString(); + + } + + + /** + * 双指针法:不使用额外的空间,首先将原来的进行扩容 + * 速度击败100%,内存击败20.93% + * @param s + * @return + */ + public String replaceSpace1(String s) { + int count = 0; // 统计空格的个数 + int sOldSize = s.length(); + for (int i = 0; i < s.length(); i++) { + if (s.charAt(i) == ' ') { + count++; + } + } + // 扩充字符串s的大小,也就是每个空格替换成"%20"之后的大小 + char[] chars = Arrays.copyOf(s.toCharArray(), s.length() + count * 2); + int sNewSize = chars.length; + // 从后先前将空格替换为"%20" + for (int i = sNewSize - 1, j = sOldSize - 1; j < i; i--, j--) { + if (chars[j] != ' ') { + chars[i] = chars[j]; + } else { + chars[i] = '0'; + chars[i - 1] = '2'; + chars[i - 2] = '%'; + i -= 2; + } + } + return new String(chars); + } +} diff --git a/Leecode/src/main/java/com/markilue/leecode/string/second/T01_ReverseString.java b/Leecode/src/main/java/com/markilue/leecode/string/second/T01_ReverseString.java new file mode 100644 index 0000000..609d5f7 --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/string/second/T01_ReverseString.java @@ -0,0 +1,87 @@ +package com.markilue.leecode.string.second; + +import org.junit.Test; + +import java.util.Arrays; + +/** + *@BelongsProject: Leecode + *@BelongsPackage: com.markilue.leecode.string.second + *@Author: dingjiawen + *@CreateTime: 2022-12-28 12:00 + *@Description: + * TODO 二刷力扣344题 反转字符串: + * 编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 s 的形式给出。 + * 不要给另外的数组分配额外的空间,你必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题 + *@Version: 1.0 + */ +public class T01_ReverseString { + + @Test + public void test(){ + char[] s = {'h', 'e', 'l', 'l', 'o'}; + reverseString(s); + System.out.println(Arrays.toString(s)); + } + + /** + * 思路:两头指针分别对换 + * 速度击败100%,内存击败15.55% + * @param s + */ + public void reverseString(char[] s) { + int left=0; + int right=s.length-1; + while (left chars.length-1){ + reverse(chars,i, chars.length-1); + }else { + reverse(chars,i,i+k-1); + } + } + return new String(chars); + + } + public void reverse(char[] s, int startIndex,int endIndex) { + char temp; + while (startIndex