diff --git a/Leecode/src/main/java/com/markilue/leecode/hot100/T01_TwoSum.java b/Leecode/src/main/java/com/markilue/leecode/hot100/T01_TwoSum.java new file mode 100644 index 0000000..91b0f48 --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/hot100/T01_TwoSum.java @@ -0,0 +1,96 @@ +package com.markilue.leecode.hot100; + +import org.junit.Test; + +import java.util.HashMap; +import java.util.Map; + +/** + *@BelongsProject: Leecode + *@BelongsPackage: com.markilue.leecode.hot100 + *@Author: markilue + *@CreateTime: 2023-02-27 10:47 + *@Description: + * TODO 力扣第1题: + * 给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。 + * 你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。 + * 你可以按任意顺序返回答案。 + *@Version: 1.0 + */ +public class T01_TwoSum { + + @Test + public void test(){ + int[] nums = {2, 7, 11, 15}; + int target = 9; + System.out.println(twoSum(nums,target)); + } + + /** + * map记录 + * 速度击败77.1% 内存击败30.65% 2ms + * @param nums + * @param target + * @return + */ + public int[] twoSum(int[] nums, int target) { + + HashMap map = new HashMap<>();// + int need = 0; + Integer index; + for (int i = 0; i < nums.length; i++) { + need = target - nums[i]; + index = map.getOrDefault(need, -1); + if (index != -1) { + return new int[]{index, i};//找到了 + } else { + map.put(nums[i], i); + } + } + + return new int[2]; + + } + + + /** + * 官方最快 + * 类似于双指针 + * 速度击败100% 内存击败30.65% 0ms + * @param nums + * @param target + * @return + */ + public int[] twoSum1(int[] nums, int target) { + Map map = new HashMap<>(); + + int[] arr = new int[2]; + + int left = 0; + int right = nums.length-1; + + while(left<=right){ + if(map.containsKey(nums[left])){ + arr[0] = map.get(nums[left]); + arr[1] = left; + return arr; + } else { + map.put(target-nums[left],left); + } + + if(map.containsKey(nums[right])){ + arr[0] = map.get(nums[right]); + arr[1] = right; + + return arr; + } else { + map.put(target-nums[right],right); + } + + left++; + right--; + } + + return arr; + } +} diff --git a/Leecode/src/main/java/com/markilue/leecode/hot100/T02_AddTwoNumbers.java b/Leecode/src/main/java/com/markilue/leecode/hot100/T02_AddTwoNumbers.java new file mode 100644 index 0000000..b730228 --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/hot100/T02_AddTwoNumbers.java @@ -0,0 +1,100 @@ +package com.markilue.leecode.hot100; + +import com.markilue.leecode.listnode.ListNode; + +/** + *@BelongsProject: Leecode + *@BelongsPackage: com.markilue.leecode.hot100 + *@Author: markilue + *@CreateTime: 2023-02-27 11:15 + *@Description: + * TODO 力扣2题 两数相加: + * 给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。 + * 请你将两个数相加,并以相同形式返回一个表示和的链表。 + * 你可以假设除了数字 0 之外,这两个数都不会以 0 开头。 + *@Version: 1.0 + */ +public class T02_AddTwoNumbers { + + + /** + * 思路:递归法 每个节点只能存储一个数字,多的数字需要进位 + * 速度击败100% 内存击败45.35% 1ms + * @param l1 + * @param l2 + * @return + */ + public ListNode addTwoNumbers(ListNode l1, ListNode l2) { + + return addTwoNumbers(l1, l2, false); + } + + + /** + * + * @param l1 + * @param l2 + * @param flag 是否需要进位 + * @return + */ + public ListNode addTwoNumbers(ListNode l1, ListNode l2, boolean flag) { + //为了公共统一,如果某一个为null,可以给他初始化 + if (l1 == null && l2 == null) { + if (flag) return new ListNode(1); + return null; + } else if (l1 == null) { + l1 = new ListNode(0); + } else if (l2 == null) { + l2 = new ListNode(0); + } + + ListNode fakeHead = new ListNode(0); + int var = l1.val + l2.val; + if (flag) { + var += 1; + } + fakeHead.val = var % 10; + fakeHead.next = addTwoNumbers(l1.next, l2.next, var >= 10); + + return fakeHead; + + + } + + + /** + * 官方解法: 使用head,tail指针进行记录 值得借鉴 + * 速度击败100% 内存击败94.81% 1ms + * @param l1 + * @param l2 + * @return + */ + public ListNode addTwoNumbers1(ListNode l1, ListNode l2) { + ListNode head = null, tail = null; + int carry = 0; + while (l1 != null || l2 != null) { + int n1 = l1 != null ? l1.val : 0; + int n2 = l2 != null ? l2.val : 0; + int sum = n1 + n2 + carry; + if (head == null) { + head = tail = new ListNode(sum % 10); + } else { + tail.next = new ListNode(sum % 10); + tail = tail.next; + } + carry = sum / 10; + if (l1 != null) { + l1 = l1.next; + } + if (l2 != null) { + l2 = l2.next; + } + } + if (carry > 0) { + tail.next = new ListNode(carry); + } + return head; + } + + +} diff --git a/Leecode/src/main/java/com/markilue/leecode/hot100/T03_LengthOfLongestSubstring.java b/Leecode/src/main/java/com/markilue/leecode/hot100/T03_LengthOfLongestSubstring.java new file mode 100644 index 0000000..5447e5f --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/hot100/T03_LengthOfLongestSubstring.java @@ -0,0 +1,109 @@ +package com.markilue.leecode.hot100; + +import org.junit.Test; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; + +/** + *@BelongsProject: Leecode + *@BelongsPackage: com.markilue.leecode.hot100 + *@Author: markilue + *@CreateTime: 2023-02-27 12:46 + *@Description: + * TODO 力扣3题 无重复字符的最长子串: + * 给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。 + *@Version: 1.0 + */ +public class T03_LengthOfLongestSubstring { + + + @Test + public void test() { + String s = "dvdf"; + String s1 = "abba"; + System.out.println(lengthOfLongestSubstring(s1)); + } + + + /** + * 思路:注意是子串,不是子序列 + * 使用一个hashmap记录之前是否有过这个单词 + * 速度击败87.4% 内存击败75.84% 4ms + * @param s + * @return + */ + public int lengthOfLongestSubstring(String s) { + + char[] chars = s.toCharArray(); + Map map = new HashMap<>();// + int maxLength = 0; + int lastIndex = 0; + int length = 0; + + for (int i = 0; i < chars.length; i++) { + if (map.containsKey(chars[i])) { + lastIndex = Math.max(lastIndex, map.get(chars[i]) + 1);//上次存在,索引就挪到这个词的下一个 + } + length = i - lastIndex + 1;//长度 + if (length > maxLength) maxLength = length; + map.put(chars[i], i);//如果存在就会覆盖 + + } + return maxLength; + + } + + + /** + * 官方最快:使用数组来代替map + * 速度击败1005 内存击败68.17% 1ms + * @param s + * @return + */ + public int lengthOfLongestSubstring1(String s) { + int[] last = new int[128]; + for(int i = 0; i < 128; i++) { + last[i] = -1; + } + int n = s.length(); + + int res = 0; + int start = 0; + for(int i = 0; i < n; i++) { + int index = s.charAt(i); + start = Math.max(start, last[index] + 1); + res = Math.max(res, i - start + 1); + last[index] = i; + } + + return res; + } + + + /** + * 评论区动态规划法 + * 速度击败100% 内存击败91.56% 1ms + * @param s + * @return + */ + public int lengthOfLongestSubstring2(String s) { + int m = s.length(); + if(m==0) { + return 0; + } + int num =1; //初始值表示以s的第一个字符为结束的不重复的最长子串 + int max =1; + for(int i=1;i= n || nums1[aStart] < nums2[bStart])) {//判断条件是关键 + right = nums1[aStart++]; + } else { + right = nums2[bStart++]; + } + } + if ((len & 1) == 0) + return (left + right) / 2.0; + else + return right; + } + + + /** + * 时间复杂度O(log(m+n)) 每次比较k/2的位置 抛弃一半 + * 速度击败100% 内存击败45.86% 1ms + * @param nums1 + * @param nums2 + * @return + */ + public double findMedianSortedArrays1(int[] nums1, int[] nums2) { + int n = nums1.length; + int m = nums2.length; + int left = (n + m + 1) / 2; + int right = (n + m + 2) / 2; + //将偶数和奇数的情况合并,如果是奇数,会求两次同样的 k 。 + return (getKth(nums1, 0, n - 1, nums2, 0, m - 1, left) + getKth(nums1, 0, n - 1, nums2, 0, m - 1, right)) * 0.5; + } + + private int getKth(int[] nums1, int start1, int end1, int[] nums2, int start2, int end2, int k) { + int len1 = end1 - start1 + 1; + int len2 = end2 - start2 + 1; + //让 len1 的长度小于 len2,这样就能保证如果有数组空了,一定是 len1 + if (len1 > len2) return getKth(nums2, start2, end2, nums1, start1, end1, k); + if (len1 == 0) return nums2[start2 + k - 1]; + + if (k == 1) return Math.min(nums1[start1], nums2[start2]); + //会直接比较k/2的位置 + int i = start1 + Math.min(len1, k / 2) - 1; + int j = start2 + Math.min(len2, k / 2) - 1; + + if (nums1[i] > nums2[j]) { + return getKth(nums1, start1, end1, nums2, j + 1, end2, k - (j - start2 + 1)); + } + else { + return getKth(nums1, i + 1, end1, nums2, start2, end2, k - (i - start1 + 1)); + } + } + +}