commit bc35fd83f4bdf93fdf60bcc7806964359643d79e Author: whai Date: Fri Dec 1 21:20:53 2023 +0800 初始化 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e80d60f --- /dev/null +++ b/.gitignore @@ -0,0 +1,45 @@ +HELP.md +docker/ +target/ +img/ +files/ +logs/ +**/node_modules/ +**/dist/ +**/.idea/ +**/**.jar +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ + + +### maven ### +.mvn/ diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..c4251f0 --- /dev/null +++ b/pom.xml @@ -0,0 +1,22 @@ + + + 4.0.0 + + org.example + LeetCode + 1.0-SNAPSHOT + + UTF-8 + 1.8 + 1.8 + + + + + + + + + diff --git a/src/main/java/cn/whaifree/leetCode/LeetCode001.java b/src/main/java/cn/whaifree/leetCode/LeetCode001.java new file mode 100644 index 0000000..1b1927b --- /dev/null +++ b/src/main/java/cn/whaifree/leetCode/LeetCode001.java @@ -0,0 +1,65 @@ +package cn.whaifree.leetCode; + +import java.util.HashMap; +import java.util.Map; + +/** + * + * 给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target  的那 两个 整数,并返回它们的数组下标。 + * + * 你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。 + * + * 你可以按任意顺序返回答案。 + * + * 来源:力扣(LeetCode) + * 链接:https://leetcode.cn/problems/two-sum + * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 + * + * + * + * 输入:nums = [2,7,11,15], target = 9 + * 输出:[0,1] + * 解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。 + * + * + * @author whaifree + * @package cn.whaifree.leetCode + * @Date: 2022/9/13 20:54 + */ +public class LeetCode001 { + + + /** + * map存储,key为nums内的值,value为下标 + * @param nums + * @param target + * @return + */ + public int[] twoSum(int[] nums, int target) { + + Map map = new HashMap<>(); + int key; + for (int i = 0; i < nums.length; i++) { + //如果包含匹配的元素即输出下标 + + key = target - nums[i]; + if (map.containsKey(key)){ + return new int[]{map.get(key),i}; + }else { + map.put(nums[i],i); + } + //不包含匹配的元素则增加到map中 + } + + return null; + + } + + public static void main(String[] args) { + int[] ints = new LeetCode001().twoSum(new int[]{2, 7, 11, 15}, 13); + for (int anInt : ints) { + System.out.println(anInt); + } + } + +} diff --git a/src/main/java/cn/whaifree/leetCode/LeetCode002.java b/src/main/java/cn/whaifree/leetCode/LeetCode002.java new file mode 100644 index 0000000..9512659 --- /dev/null +++ b/src/main/java/cn/whaifree/leetCode/LeetCode002.java @@ -0,0 +1,116 @@ +package cn.whaifree.leetCode; + +/** + * + * + * 给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。 + * + * 请你将两个数相加,并以相同形式返回一个表示和的链表。 + * + * 你可以假设除了数字 0 之外,这两个数都不会以 0 开头。 + * + * 来源:力扣(LeetCode) + * 链接:https://leetcode.cn/problems/add-two-numbers + * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 + * + * @author whaifree + * @package cn.whaifree.leetCode + * @Date: 2022/9/13 21:18 + */ +public class LeetCode002 { + + + /** + * l1和l2向下移动,让答案节点的值为l1+l2+carry,carry表示上一节点所带来的增1 + * @param l1 + * @param l2 + * @return + */ + public ListNode addTwoNumbers(ListNode l1, ListNode l2) { + + ListNode ansNode=new ListNode(0); + ListNode ansIndex = ansNode; + int carry = 0; + while (l1!=null||l2!=null||carry!=0){ + //如果l1和l2都空了,但carry为1,还是要多一个1节点的。 + int val1 = l1==null?0:l1.val; + int val2 = l2==null?0:l2.val; + int nodeVal = val1 + val2 + carry; + + carry = nodeVal / 10; + ansIndex.next = new ListNode(nodeVal % 10); + ansIndex = ansIndex.next; + + //一旦l1为空,直接把l2接上 + if (l1!=null){ + l1 = l1.next; + } + //l2为空,把l1接上 + if (l2!=null){ + l2 = l2.next; + } + } + + return ansNode.next; + + + + } + + + /** + * 从坐到右挨个相加, + * val%10 取得余数 + * val//10 取得整数十位 + * @param l1 + * @param l2 + * @return + */ + public ListNode addTwoNumbers1(ListNode l1, ListNode l2) { + ListNode ansNode = new ListNode(0); + ListNode ansIndex = ansNode; + ListNode index1 = l1; + ListNode index2 = l2; + boolean flag = false; + while (index1 != null || index2 != null) { + //两个指针都非空的时候表示需要计算往下加。 + int val1 = index1.val; + int val2 = flag?index2.val+1:index2.val; + flag = false; + if (val1+val2<10){ + //无需进1 + ansIndex.next = new ListNode(val1+val2); + }else { + //需要进1 + ansIndex.next = new ListNode((val1+val2)-10); + flag = true; + } + + index1 = index1.next; + index2 = index2.next; + + } + + //直接追加 + if (index1 != null) { + ansIndex.next = index1; + }else { + ansIndex.next = index2; + } + + + + return ansNode.next; + + } + +} + + +class ListNode { + int val; + ListNode next; + ListNode() {} + ListNode(int val) { this.val = val; } + ListNode(int val, ListNode next) { this.val = val; this.next = next; } +} diff --git a/src/main/java/cn/whaifree/leetCode/LeetCode003.java b/src/main/java/cn/whaifree/leetCode/LeetCode003.java new file mode 100644 index 0000000..34c2022 --- /dev/null +++ b/src/main/java/cn/whaifree/leetCode/LeetCode003.java @@ -0,0 +1,107 @@ +package cn.whaifree.leetCode; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +/** + * + * 给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。 + * + *   + * + * 示例 1: + * + * 输入: s = "abcabcbb" + * 输出: 3 + * 解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。 + * 示例 2: + * + * 输入: s = "bbbbb" + * 输出: 1 + * 解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。 + * 示例 3: + * + * 输入: s = "pwwkew" + * 输出: 3 + * 解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。 + *   请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。 + *   + * + * 来源:力扣(LeetCode) + * 链接:https://leetcode.cn/problems/longest-substring-without-repeating-characters + * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 + * + * + * @author whaifree + * @package cn.whaifree.leetCode + * @Date: 2022/9/15 19:01 + */ +public class LeetCode003 { + + + /** + * 使用一个Map key为字符的值,value为字符的下标 + * 每次遇到没有的就往Map添加,并且右指针移动 + * 遇到有的,就左指针指向前一个的value + * @param s + * @return + */ + public int lengthOfLongestSubstring(String s) { + Map map = new HashMap<>(); + //获得s每个字符 + char[] chars = s.toCharArray(); + //lengthIndex作为当前长度的标志 + //maxLength用于给出最后的结果 + int maxLength = 0; + //需要两个左右指针 + int leftIndex = 0; + + for (int i = 0; i < chars.length; i++) { + if (map.containsKey(chars[i])){ + //出现过了 左指针右移到它上次出现地方的下一个位置 + //但如abba,移动到最后一个a时,left应该指向第二个b,而不是a的位置+1 + leftIndex = Math.max(leftIndex,map.get(chars[i])+1); + } + + map.put(chars[i], i); + maxLength = Math.max(maxLength, i - leftIndex + 1); + + } + + return maxLength; + + } + + public static void main(String[] args) { + System.out.println(new LeetCode003().lengthOfLongestSubstring1("abba")); + } + + + /** + * 使用Map abbcd + * @param s + * @return + */ + public int lengthOfLongestSubstring1(String s) { + + + //key为char字符,value为下标。 + Map map = new HashMap<>(); + int maxLength = 0,left = 0; + for (int i = 0; i < s.length(); i++) { + //如果出现过 + if (map.containsKey(s.charAt(i))){ + left = Math.max(left, map.get(s.charAt(i)) + 1); + } + //加入队列 + map.put(s.charAt(i),i); + //更新maxLength + maxLength = Math.max(maxLength, i - left + 1); + } + + return maxLength; + + } +} diff --git a/src/main/java/cn/whaifree/leetCode/LeetCode209.java b/src/main/java/cn/whaifree/leetCode/LeetCode209.java new file mode 100644 index 0000000..da57687 --- /dev/null +++ b/src/main/java/cn/whaifree/leetCode/LeetCode209.java @@ -0,0 +1,135 @@ +package cn.whaifree.leetCode; + +import java.util.HashMap; +import java.util.LinkedList; +import java.util.Map; +import java.util.Queue; + +/** + * + * 找出该数组中满足其和 ≥ target 的长度最小的 连续子数组 [numsl, numsl+1, ..., numsr-1, numsr] ,并返回其长度。如果不存在符合条件的子数组,返回 0 。 + * + * 来源:力扣(LeetCode) + * 链接:https://leetcode.cn/problems/minimum-size-subarray-sum + * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 + * + * 示例 1: + * + * 输入:target = 7, nums = [2,3,1,2,4,3] + * 输出:2 + * 解释:子数组 [4,3] 是该条件下的长度最小的子数组。 + * 示例 2: + * + * 输入:target = 4, nums = [1,4,4] + * 输出:1 + * 示例 3: + * + * 输入:target = 11, nums = [1,1,1,1,1,1,1,1] + * 输出:0 + * + * @author whaifree + * @package cn.whaifree.leetCode + * @Date: 2022/9/20 10:16 + */ +public class LeetCode209 { + + public int minSubArrayLen(int target, int[] nums) { + + //滑动窗口 + Queue queue = new LinkedList(); + //标记最短长度 + int shortest = 100000; + + int sum = 0; + for (int i = 0; i < nums.length; i++) { + + + queue.add(nums[i]); + if (sum + nums[i] >= target) { + //达标了,需要将shortest更新为最短的 + if (shortest>queue.size()){ + shortest = queue.size(); + } + //sum减去上一个 + sum -= queue.poll(); + } + sum += nums[i]; + } + + if (queue.size()==nums.length){ + return 0; + } + return shortest; + } + + public static void main(String[] args) { + System.out.println(new LeetCode209().minSubArrayLen2(8, new int[]{1,1,1,1,1,1,1,1})); + } + + public int minSubArrayLen1(int target, int[] nums) { + //使用队列,不停得入队,直到大于target再不停出队直到小于target + Queue queue = new LinkedList<>(); + + int sum = 0; + int shortest = 100000; + int nowSum = 0; + for (int i = 0; i < nums.length; i++) { + + + sum += nums[i]; + + //入队 + queue.add(nums[i]); + //队列内的值之和 + nowSum += nums[i]; + + while (nowSum >= target) { + if (shortest > queue.size()){ + shortest = queue.size(); + } + //不停出队 + nowSum -= queue.poll(); + } + } + + //判断nums之和小于target的情况 + if (sum < target) { + return 0; + } + + return shortest; + } + + + /** + * 使用nums数组作为队列 + * @param target + * @param nums + * @return + */ + public int minSubArrayLen2(int target, int[] nums) { + + int leftIndex = 0, rightIndex = 0; + int shortest = 100000; + int nowSum = 0; + for (int i = 0; i < nums.length; i++) { + + nowSum += nums[i]; + //入队 + rightIndex++; + while (nowSum >= target){ + //更新shortest + shortest = Math.min(shortest, rightIndex - leftIndex); + nowSum -= nums[leftIndex++]; + //出队 + } + } + + if (nums.length==rightIndex-leftIndex){ + return 0; + } + return shortest; + + } + +} diff --git a/src/main/java/cn/whaifree/leetCode/LeetCode718.java b/src/main/java/cn/whaifree/leetCode/LeetCode718.java new file mode 100644 index 0000000..ff7e02c --- /dev/null +++ b/src/main/java/cn/whaifree/leetCode/LeetCode718.java @@ -0,0 +1,131 @@ +package cn.whaifree.leetCode; + +/** + * + * 给两个整数数组 nums1 和 nums2 ,返回 两个数组中 公共的 、长度最长的子数组的长度 。 + * + * + * + * 示例 1: + * + * 输入:nums1 = [1,2,3,2,1], nums2 = [3,2,1,4,7] + * 输出:3 + * 解释:长度最长的公共子数组是 [3,2,1] 。 + * 示例 2: + * + * 输入:nums1 = [0,0,0,0,0], nums2 = [0,0,0,0,0] + * 输出:5 + * + * + * 提示: + * + * 1 <= nums1.length, nums2.length <= 1000 + * 0 <= nums1[i], nums2[i] <= 100 + * + * @author whaifree + * @package cn.whaifree.leetCode + * @Date: 2022/9/24 15:39 + */ +public class LeetCode718 { + + public static void main(String[] args) { + System.out.println(new LeetCode718().findLength(new int[]{1,2,3,2,1},new int[]{3,2,1,4,7})); + } + + + /** + * 两层循环 动态规划 + * @param nums1 + * @param nums2 + * @return + */ + public int findLength(int[] nums1, int[] nums2) { + + //存储标记 + int db[][] = new int[nums1.length+1][nums2.length+1]; + + for (int i = 0; i < nums1.length; i++) { + for (int j = 0; j < nums2.length; j++) { + //如果两个数组在某处重复,就在i-1,j-1的基础上+1,表示新已知最大子数组长度+1 + if (nums1[i]==nums2[j]){ + db[i + 1][j + 1] = db[i][j] + 1; + } + } + } + + //求得二维度最大值 + int max = 0; + for (int[] ints : db) { + for (int anInt : ints) { + max = Math.max(max, anInt); + } + } + + return max; + + } + + + /** + * 默认nums1短 nums2长 + * @param nums1 + * @param nums2 + * @return + *//* + public int findLength2(int[] nums1, int[] nums2) { + + int max = 0; + for (int i = 0; i < nums1.length; i++) { + max = Math.max(max, findMaxInTwo(nums1, 0, nums2, nums2.length-i, i)); + } + + for (int i = 0; i < nums1.length; i++) { + max = Math.max(max, findMaxInTwo(nums1, 0, nums2, nums2.length-i, i)); + } + + for (int i = 0; i < nums1.length; i++) { + max = Math.max(max, findMaxInTwo(nums1, 0, nums2, nums2.length-i, i)); + } + + + } + + *//** + * 如 findMaxInTwo({2,3,4},1,{3,4,5},0,2) 就是从两个数组中找到字串为2的公共字串长度 + * + * + * A: |*|*|*|*| + * B: |*|*|*|*|*|*| + * + * + * @param nums1 + * @param nums1Index + * @param nums2 + * @param nums2Index + * @param len + * @return + *//* + int findMaxInTwo(int[] nums1,int nums1Index ,int[] nums2,int nums2Index,int len){ + //判断是否有重复子串 + + int count = 0; + //存放现在的匹配字串长度值 + int max = 0; + for (int i = 0; i < len; i++) { + //遇到相等的就当前匹配长度++ + if (nums1[nums1Index + i] == nums2[nums2Index + i]) { + count++; + + } else { + //遇到不相等的就判断一下当前匹配字串与最大匹配字串长度 + max = Math.max(max, count); + count = 0; + } + } + + //找到最大匹配的字串长度 + return Math.max(max,count); + + }*/ + +} diff --git a/src/main/java/cn/whaifree/leetCode/Offer03.java b/src/main/java/cn/whaifree/leetCode/Offer03.java new file mode 100644 index 0000000..1b68a9f --- /dev/null +++ b/src/main/java/cn/whaifree/leetCode/Offer03.java @@ -0,0 +1,219 @@ +package cn.whaifree.leetCode; + + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +/** + * @author whaifree + * @package cn.whaifree.leetCode + * @Date: 2022/9/11 19:14 + * + * 在一个长度为 n 的数组 nums 里的所有数字都在 0~n-1 的范围内。 + * 数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。 + * + * 示例 1: + * + * 输入: + * [2, 3, 1, 0, 2, 5, 3] + * 输出:2 或 3 + *   + * + * 限制: + * + * 2 <= n <= 100000 + * + * 来源:力扣(LeetCode) + * 链接:https://leetcode.cn/problems/shu-zu-zhong-zhong-fu-de-shu-zi-lcof + * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 + */ +public class Offer03 { + public static void main(String[] args) { + + +// System.out.println(new Solution1().findRepeatNumber5(new int[]{1, 2, 3,2, 3})); + + } + + +} + +class Solution1 { + + /** + * 1. 找一个num长度的数组n,遍历统计,n内大于1输出 + * 2. Map key为数字,value自增,遍历Map获得value>1的key + * 3. 先排序,再向下找重复 + */ + + /** + * Map方法 + * @param nums + * @return + */ + public int findRepeatNumber(int[] nums) { + Map map = new HashMap(); + int integer = 0; + for (int num : nums) { + if (map.containsKey(num)){ + //原来是有这个数字的 + integer = map.get(num); + map.put(num,++integer); + }else { + //没有这个数字 + map.put(num,1); + } + } + + /** + * 遍历map的方法 + * 1. 遍历keySet的Set + * 2. 遍历Values,只能遍历Value + * 3. 遍历entrySet() + * 4. forEach遍历 + */ + //遍历map的key +// System.out.println("1. 遍历keySet的Set"); + for (Integer i : map.keySet()) { + if (map.get(i)>1){ + System.out.println(i); + } + } + +// System.out.println("3. 遍历entrySet()"); +// for (Map.Entry integerIntegerEntry : map.entrySet()) { +// System.out.println("key = " + integerIntegerEntry.getKey()); +// System.out.println("value = " + integerIntegerEntry.getValue()); +// } +// +// System.out.println("4. forEach遍历"); +// map.forEach((key,value)->{ +// System.out.println("key is "+ key); +// System.out.println("value is "+ value); +// }); + + return 0; + } + + /** + * 排序向下找重复 + * @param nums + * @return + */ + public int findRepeatNumber2(int[] nums) { + //冒泡排序 + boolean flag = true; + int c=0; + int length = nums.length; + for (int i = 0; i < length; i++) { + for (int j = 0; j < length-i-1; j++) { + if (nums[j] > nums[j+1]) { + c = nums[j+1]; + nums[j+1] = nums [j]; + nums[j] = c; + + } + } + } + + /*for (int num : nums) { + System.out.println(num); + }*/ + //排序完成 + + /** + * 在已经排序的里面找到有出现大于两次的 + */ + return 0; + } + + /** + * + * 完成 + * + * 题目,找出任意一个重复的数字。 + * @param nums + * @return + */ + public int findRepeatNumber3(int[] nums) { + Map map = new HashMap(); + for (int num : nums) { + if (map.containsKey(num)){ + //原来是有这个数字的,证明不是第一次出现了,直接输出就是结果 + return num; + }else { + //没有这个数字,首次出现 + map.put(num,1); + } + } + return 0; + + } + + + /** + * 使用HashSet + * @param nums + * @return + */ + + public int findRepeatNumber4(int[] nums) { + Set set = new HashSet<>(); + for (int num : nums) { + if (set.contains(num)){ + //有这个数字直接输出 + return num; + }else { + //没有这个数字就增加在set中 + set.add(num); + } + } + return 0; + } + + /** + * 下标法:不停交换元素使得元素和对应下标相等。 + * nums[i]=i + * nums[nums[i]] = nums[i] 下标与元素值相等 + * + * 通过索引映射对应的值,起到与字典等价的作用。 + * 长度为 n 的数组 nums 里的所有数字都在 0~n-1 的范围内。即能够确定索引的大小。 + * + * @param nums + * @return + */ + public int findRepeatNumber5(int[] nums){ + + int flag = 0; + int i = 0; + while (i < nums.length){ + + //遍历每个数 + //1. 不在正确位置上,进行交换 + // 如果交换的位置已经有正确的数字,直接输出结果 + //2. 在正确的位置上,continue + + if (nums[i]!=i){ + //需要进行交换 + if (nums[nums[i]]==nums[i]){ + //在该位置已经有正确的位置提前占好了 + return nums[i]; + } + //交换 nums[nums[i]]和nums[i] + flag = nums[i]; + nums[i] = nums[nums[i]]; + nums[flag] = flag; + }else { + i++; + } + + + } + + return -1; + } + + +} \ No newline at end of file