1、两数之和 II - 输入有序数组

问题:给定一个已按照 非递减顺序排列  的整数数组 numbers ,请你从数组中找出两个数满足相加之和等于目标数 target 。

函数应该以长度为 2 的整数数组的形式返回这两个数的下标值。numbers 的下标 从 1 开始计数 ,所以答案数组应当满足 1 <= answer[0] < answer[1] <= numbers.length 。

你可以假设每个输入 只对应唯一的答案 ,而且你 不可以 重复使用相同的元素。 

示例 1:

输入:numbers = [2,7,11,15], target = 9
输出:[1,2]
解释:2 与 7 之和等于目标数 9 。因此 index1 = 1, index2 = 2 。
示例 2:

输入:numbers = [2,3,4], target = 6
输出:[1,3]
示例 3:

输入:numbers = [-1,0], target = -1
输出:[1,2]

 1 package LeetCode.test2_shuangzhizheng;
 2 
 3 import java.util.Arrays;
 4 
 5 public class ques_167_两数之和II_输入有序数组 {
 6     public static void main(String[] args) {
 7         int[] numbers = {2, 7, 11, 15};
 8 //        int[] numbers = {2, 3, 4};
 9         int target = 9;
10 //        int target = 6;
11         System.out.println(Arrays.toString(twoSum(numbers, target)));
12     }
13 
14     public static int[] twoSum(int[] numbers, int target) {
15         int left = 0;
16         int right = numbers.length - 1;
17         while (left < right) {
18             if (numbers[left] + numbers[right] > target) {
19                 right--;
20             } else if (numbers[left] + numbers[right] < target) {
21                 left++;
22             } else {
23                 break;
24             }
25         }
26         return new int[]{left + 1, right + 1};
27     }
28 }
View Code

2、合并两个有序数组

问题:给你两个按 非递减顺序 排列的整数数组 nums1 和 nums2,另有两个整数 m 和 n ,分别表示 nums1 和 nums2 中的元素数目。

请你 合并 nums2 到 nums1 中,使合并后的数组同样按 非递减顺序 排列。

注意:最终,合并后数组不应由函数返回,而是存储在数组 nums1 中。为了应对这种情况,nums1 的初始长度为 m + n,其中前 m 个元素表示应合并的元素,后 n 个元素为 0 ,应忽略。nums2 的长度为 n 。

示例 1:

输入:nums1 = [1,2,3,0,0,0], m = 3, nums2 = [2,5,6], n = 3
输出:[1,2,2,3,5,6]
解释:需要合并 [1,2,3] 和 [2,5,6] 。
合并结果是 [1,2,2,3,5,6] ,其中斜体加粗标注的为 nums1 中的元素。
示例 2:

输入:nums1 = [1], m = 1, nums2 = [], n = 0
输出:[1]
解释:需要合并 [1] 和 [] 。
合并结果是 [1] 。
示例 3:

输入:nums1 = [0], m = 0, nums2 = [1], n = 1
输出:[1]
解释:需要合并的数组是 [] 和 [1] 。
合并结果是 [1] 。
注意,因为 m = 0 ,所以 nums1 中没有元素。nums1 中仅存的 0 仅仅是为了确保合并结果可以顺利存放到 nums1 中。

 1 package LeetCode.test2_shuangzhizheng;
 2 
 3 import java.util.Arrays;
 4 
 5 /**
 6  * 两种情况:m>=0,n>=0  n>=0
 7  * (第一种运行过程中也可能会变为第二种情况)
 8  */
 9 public class ques_88_合并两个有序数组 {
10     public static void main(String[] args) {
11 //        int[] nums1 = {1, 2, 3, 0, 0, 0};
12 //        int m = 3;
13 //        int[] nums2 = {2, 5, 6};
14 //        int n = 3;
15 
16 //        int[] nums1 = {1};
17 //        int m = 1;
18 //        int[] nums2 = {};
19 //        int n = 0;
20 
21 //        int[] nums1 = {0};
22 //        int m = 0;
23 //        int[] nums2 = {1};
24 //        int n = 1;
25 
26         int[] nums1 = {2, 0};
27         int m = 1;
28         int[] nums2 = {1};
29         int n = 1;
30         merge(nums1, m, nums2, n);
31     }
32 
33     public static void merge(int[] nums1, int m, int[] nums2, int n) {
34         int pos = m-- + n-- - 1;  // 当前pos = m + n - 1
35         while (m >= 0 && n >= 0) {  // 当前m = m-1, n = n-1 (第一种情况)
36             nums1[pos--] = nums2[n] > nums1[m] ? nums2[n--] : nums1[m--];
37         }
38         while (n >= 0) {  // (第二种情况)
39             nums1[pos--] = nums2[n--];
40         }
41         System.out.println(Arrays.toString(nums1));
42     }
43 }
View Code

3、环形链表II

问题:给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。

如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。

如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。不允许修改 链表。

示例 1:

输入:head = [3,2,0,-4], pos = 1
输出:返回索引为 1 的链表节点
解释:链表中有一个环,其尾部连接到第二个节点。
示例 2:

输入:head = [1,2], pos = 0
输出:返回索引为 0 的链表节点
解释:链表中有一个环,其尾部连接到第一个节点。
示例 3:

输入:head = [1], pos = -1
输出:返回 null
解释:链表中没有环。

 1 package LeetCode.test2_shuangzhizheng;
 2 
 3 public class ques_142_环形链表II {
 4     public static class ListNode {
 5         int value;
 6         ListNode next;
 7 
 8         ListNode(){
 9 
10         }
11 
12         ListNode(int value) {
13             this.value = value;
14         }
15     }
16 
17     public static void main(String[] args) {
18 
19     }
20 
21     public static ListNode detectCycle(ListNode head) {
22         if (head == null) {
23             return null;
24         }
25         ListNode fast = head;
26         ListNode slow = head;
27         while (fast != null && fast.next != null) {  //至少有两个节点
28             fast = fast.next.next;
29             slow = slow.next;
30             //是带环链表
31             if (fast == slow) {
32                 break;
33             }
34         }
35         //不是带环链表(fast==slow==null或者只有一个head节点)
36         if (fast == null || fast.next == null) {
37             return null;
38         }
39         fast = head;
40         while (fast != slow) {
41             fast = fast.next;
42             slow = slow.next;
43         }
44         return fast;
45     }
46 }
View Code

4、最小覆盖子串

问题:给你一个字符串 s 、一个字符串 t 。返回 s 中涵盖 t 所有字符的最小子串。如果 s 中不存在涵盖 t 所有字符的子串,则返回空字符串 "" 。

注意:

对于 t 中重复字符,我们寻找的子字符串中该字符数量必须不少于 t 中该字符数量。
如果 s 中存在这样的子串,我们保证它是唯一的答案。

示例 1:

输入:s = "ADOBECODEBANC", t = "ABC"
输出:"BANC"
示例 2:

输入:s = "a", t = "a"
输出:"a"
示例 3:

输入: s = "a", t = "aa"
输出: ""
解释: t 中两个字符 'a' 均应包含在 s 的子串中,
因此没有符合条件的子字符串,返回空字符串。

思路:

 1 /**
 2  * 思路:以s = "KADOBECODEBANC";t = "ABC"为例。
 3  *  flag[K]=0 -> flag[K]=-1  count = 3
 4  *  flag[A]=1 -> flag[A]=0   count = 2
 5  *              ...... D,O,E=-1
 6  *  flag[C]=1 -> flag[C]=0   count = 0  此时,left=0,right=6
 7  *
 8  *  ans = KADOBEC
 9  *  flag[K]=-1 -> flag[K]=0  count=0  left = 1
10  *  ans = ADOBEC  min = 6
11  *
12  *  flag[A]=0 -> flag[A]=1  count=1  left = 2
13  *  退出while(count==0)循环,此时right=7   字母O位置
14  *  flag[O]=-1 -> flag[O]=-2  count = 1
15  *              ......  D,E,B = -2,-2,-1
16  *  flag[A]=1 -> flag[A]=0   count = 0   此时,left=2,right=11
17  *
18  *  ans = DOBECODEBA  >  6 ,所以 ans = ADOBEC
19  *  flag[D]=-2 -> flag[D]=-1  count=0  left = 3
20  *  flag[O]=-2 -> flag[O]=-1  count=0  left = 4
21  *  flag[B]=-1 -> flag[B]=0  count=0  left = 5
22  *  flag[E]=-2 -> flag[E]=-1  count=0  left = 6
23  *  ans = CODEBA = 6 ,所以 ans = ADOBEC    CODEBA
24  *
25  *  flag[C]=0 -> flag[C]=1  count=1  left = 7
26  *  退出while(count==0)循环,此时right=12   字母N位置
27  *              ......
28  *  ans = BANC
29  *
30  *  ans变化过程:KADOBEC->ADOBEC->DOBECODEBA->CODEBA->ODEBANC->BANC(ans中最小的)
31  */
 1 package LeetCode.test2_shuangzhizheng;
 2 
 3 public class ques_76_最小覆盖子串 {
 4     public static void main(String[] args) {
 5         String s = "KADOBECODEBANC";
 6         String t = "ABC";
 7         System.out.println(minWindow(s, t));
 8     }
 9 
10     public static String minWindow(String s, String t) {
11         int[] flag = new int[128];
12         //记录t字符串每个字符出现的次数
13         for (int i = 0; i < t.length(); i++) {
14             flag[t.charAt(i)]++;
15         }
16 
17         int left = 0;  // 窗口左边界
18         int right = 0; // 窗口右边界
19         int count = t.length(); // 需要指定元素的个数
20         int min = Integer.MAX_VALUE; // 最下窗口大小
21         String ans = ""; // 记录结果
22 
23         while (right < s.length()) {
24             char ch = s.charAt(right);
25             if (flag[ch] > 0) { //如果ch是需要的字符,count减一
26                 count--;
27             }
28             flag[ch]--; //如果ch是需要的字符flag[ch]--的值最小为0,如果ch不是需要的字符flag[ch]--的值为负数
29             while (count == 0) {
30                 if (min > right - left + 1) { // 最优字符串
31                     min = right - left + 1;
32                     ans = s.substring(left, right + 1);
33                 }
34                 ch = s.charAt(left);
35                 if (flag[ch] == 0) { //flag[ch]==0说明这个ch是需要的字符,并且刚好包含一个,把它去除就不能完全覆盖t
36                     count++;
37                 }
38                 flag[ch]++;  // 需要的ch数量加1
39                 left++;
40             }
41             right++;
42         }
43         return ans;
44     }
45 }
View Code

5、平方数之和

问题:给定一个非负整数 c ,你要判断是否存在两个整数 a 和 b,使得 a2 + b2 = c 。

示例 1:

输入:c = 5
输出:true
解释:1 * 1 + 2 * 2 = 5
示例 2:

输入:c = 3
输出:false
示例 3:

输入:c = 4
输出:true
示例 4:

输入:c = 2
输出:true
示例 5:

输入:c = 1
输出:true

 1 package LeetCode.test2_shuangzhizheng;
 2 
 3 /**
 4  * 双指针法
 5  * 如果生成数较大,则大值减小
 6  * 生成数较小,则小值变大
 7  */
 8 public class ques_633_平方数之和 {
 9     public static void main(String[] args) {
10         int c = 2147483600;
11         System.out.println(judgeSquareSum(c));
12     }
13 
14     public static boolean judgeSquareSum(int c) {
15         if (c < 0) {
16             return false;
17         }
18         double left = 0;
19         double right = Math.floor(Math.sqrt(c));
20         while (left <= right) {
21             double sum = left * left + right * right;
22             if (sum > c) {
23                 right--;
24             } else if (sum < c) {
25                 left++;
26             } else {
27                 return true;
28             }
29         }
30         return false;
31     }
32 }
View Code

6、验证回文字符串Ⅱ

问题:给定一个非空字符串 s,最多删除一个字符。判断是否能成为回文字符串。

示例 1:

输入: s = "aba"
输出: true
示例 2:

输入: s = "abca"
输出: true
解释: 你可以删除c字符。
示例 3:

输入: s = "abc"
输出: false

思路:在使用双指针遍历字符串时,如果出现两个指针指向的字符不相等的情况,试着删除一个字符,再判断删除完之后的字符串是否是回文字符串。

在判断是否为回文字符串时,不需要判断整个字符串,因为左指针左边和右指针右边的字符之前已经判断过具有对称性质,所以只需要判断中间的子字符串即可。

在试着删除字符时,既可以删除左指针指向的字符,也可以删除右指针指向的字符.(important)

 1 package LeetCode.test2_shuangzhizheng;
 2 
 3 public class ques_680_验证回文字符串Ⅱ {
 4     public static void main(String[] args) {
 5 //        String s = "aba";
 6 //        String s = "deeee";
 7         String s = "cupffpucu";
 8 //        String s = "abddca";
 9 //        String s = "cxccxcx";
10         System.out.println(validPalindrome(s));
11     }
12 
13     public static boolean validPalindrome(String s) {
14         for (int i = 0, j = s.length() - 1; i < j; i++, j--) {
15             if (s.charAt(i) != s.charAt(j)) {
16                 return isPalindrome(s, i + 1, j) || isPalindrome(s, i, j - 1);
17             }
18         }
19         return true;
20     }
21 
22     public static boolean isPalindrome(String s, int i, int j) {
23         while (i < j) {
24             if (s.charAt(i++) != s.charAt(j--)) {
25                 return false;
26             }
27         }
28         return true;
29     }
30 }
View Code

7、通过删除字母匹配到字典里最长单词

问题:给你一个字符串 s 和一个字符串数组 dictionary ,找出并返回 dictionary 中最长的字符串,该字符串可以通过删除 s 中的某些字符得到。

如果答案不止一个,返回长度最长且字母序最小的字符串。如果答案不存在,则返回空字符串。

示例 1:

输入:s = "abpcplea", dictionary = ["ale","apple","monkey","plea"]
输出:"apple"
示例 2:

输入:s = "abpcplea", dictionary = ["a","b","c"]
输出:"a"

 1 package LeetCode.test2_shuangzhizheng;
 2 
 3 import java.util.*;
 4 
 5 public class ques_524_通过删除字母匹配到字典里最长单词 {
 6     public static void main(String[] args) {
 7         String s = "abpcplea";
 8         List<String> dictionary = new ArrayList<>();
 9         dictionary.add("ale");
10         dictionary.add("apple");
11         dictionary.add("monkey");
12         dictionary.add("plea");
13         System.out.println(findLongestWord(s, dictionary));
14 
15     }
16 
17     public static String findLongestWord(String s, List<String> dictionary) {
18         String res = "";
19         for (String str : dictionary) {
20             // 如果结果字符串比当前遍历的字符串更长,那就可以直接跳过
21             // 如果两个字符串长度相等,那就比较一下字典顺序,如果当前遍历的字符串更小,就跳过
22             if (res.length() > str.length() || (res.length() == str.length() && res.compareTo(str) < 0)) {
23                 continue;
24             }
25             // 如果是子序列,就覆盖结果字符串
26             if (isSubStr(s, str)) {
27                 res = str;
28             }
29         }
30         return res;
31     }
32 
33     public static boolean isSubStr(String s, String str) { // 判断是否是子序列
34         int i = 0;
35         int j = 0;
36         while (i < s.length() && j < str.length()) {
37             if (s.charAt(i) == str.charAt(j)) {
38                 j++;
39             }
40             i++;
41         }
42         return j == str.length();
43     }
44 }
View Code

8、至多包含K个不同字符的最长子串

问题:给定一个字符串s ,找出至多包含k个不同字符的最长子串T。

示例 1:

输入: s = "eceba", k = 2

输出: 3

解释: 则 T 为 "ece",所以长度为 3。

示例 2:

输入: s = "aa", k = 1

输出: 2

解释: 则 T 为 "aa",所以长度为 2。

思路:双指针,指针中间的是可能的答案。符合要求右指针向右扩,否则更新答案,左指针往右缩。

 1 package LeetCode.test2_shuangzhizheng;
 2 
 3 import java.util.Collections;
 4 import java.util.HashMap;
 5 import java.util.Map;
 6 
 7 /**
 8  * eg:  s = "ecebeea"   k = 2
 9  * e->0  left=0  right=1  max=(0,1-0)=1
10  * e->0 c->1  left=0 right=2  max=(1,2-0)=2
11  * e->2 c->1  left=0 right=3  max=(2,3-0)=3
12  * e->2 c->1 b->3  (e->2 b->3)  left=2  right=4  max=(3,4-2)=3
13  * e->4 b->3  left=2  right=5   max=(3,5-2)=3
14  * e->5 b->3  left=2  right=6   max=(3,6-2)=4
15  * e->5 b->3 a->6 (e->5 a->6)  left=4  right=7  max=(4,7-24)=4
16  */
17 
18 public class ques_340_至多包含K个不同字符的最长子串 {
19     public static void main(String[] args) {
20         String s = "eceba";
21         int k = 2;
22         System.out.println(lengthOfLongestSubstringKDistinct(s, k));
23     }
24 
25     public static int lengthOfLongestSubstringKDistinct(String s, int k) {
26         if (s.length() == k) {
27             return s.length();
28         }
29         int left = 0;
30         int right = 0;
31         Map<Character, Integer> map = new HashMap<>();
32         int max = 0;
33         while (right < s.length()) {
34             if (map.size() <= k) {
35                 map.put(s.charAt(right), right);
36                 right++;
37             }
38             if (map.size() == k + 1) {
39                 int index = Collections.min(map.values());
40                 map.remove(s.charAt(index));
41                 left = index + 1;
42             }
43             max = Math.max(max, right - left);
44         }
45         return max;
46     }
47 }
View Code
posted on 2021-11-28 20:24  晨曦生辉耀匕尖  阅读(46)  评论(0编辑  收藏  举报