https://leetcode-cn.com/tag/two-pointers/
题目汇总
167. 两数之和 II - 输入有序数组简单[✔]
209. 长度最小的子数组中等[✔]
234. 回文链表简单(??)
283. 移动零简单
287. 寻找重复数中等(???)
344. 反转字符串简单 [✔]
345. 反转字符串中的元音字母简单
349. 两个数组的交集简单
167. 两数之和 II - 输入有序数组简单
给定一个已按照升序排列的有序数组,找到两个数使得它们相加之和等于目标数。
函数应该返回这两个下标值index1 和 index2,其中 index1 必须小于 index2。
说明:
返回的下标值(index1 和 index2)不是从零开始的。
你可以假设每个输入只对应唯一的答案,而且你不可以重复使用相同的元素。
示例:
输入: numbers = [2, 7, 11, 15], target = 9
输出: [1,2]
解释: 2 与 7 之和等于目标数 9 。因此 index1 = 1, index2 = 2 。
思路:双指针,最基础的一道题
class Solution {//执行用时 :1 ms, 在所有 Java 提交中击败了97.07%的用户
public int[] twoSum(int[] numbers, int target) {
int[] result = new int[2];//存放输出数组
if(numbers == null || numbers.length < 2)
return result;
int i = 0;
int j = numbers.length - 1;
while(i < j){
int sum = numbers[i] + numbers[j];
if(sum == target){
result[0] = i + 1;//下标是从1开始的,要加1
result[1] = j + 1;
return result;
}else if(sum > target){
j--;
}
else{
i++;
}
}
return result;
}
}
209. 长度最小的子数组中等
给定一个含有 n 个正整数的数组和一个正整数 s ,找出该数组中满足其和 ≥ s 的长度最小的连续子数组,并返回其长度。如果不存在符合条件的连续子数组,返回 0。
示例:
输入:s = 7, nums = [2,3,1,2,4,3]
输出: 2
解释: 子数组[4,3]
是该条件下的长度最小的连续子数组。
进阶:
如果你已经完成了O(n) 时间复杂度的解法, 请尝试 O(n log n) 时间复杂度的解法。
思路:双指针
设置两个指针表示一个滑动窗口,窗口中的元素小于目标值,右指针向右移,扩大窗口。窗口中的元素大于目标值,比较当前窗口大小是否为最小值,左指针向右移,缩小窗口。
class Solution {//执行用时 :2 ms, 在所有 Java 提交中击败了84.80%的用户
public int minSubArrayLen(int s, int[] nums) {//执行用时 :2 ms
if(nums == null || nums.length <= 0)
return 0;
int left = 0;
int sum = 0;
int min = Integer.MAX_VALUE;
for(int right=0;right= s){
min = Math.min(min, right - left + 1);
sum -= nums[left++];//减小区间
}
}
return min == Integer.MAX_VALUE ? 0 : min;
}
}
234. 回文链表简单
请判断一个链表是否为回文链表。
示例 1:
输入: 1->2
输出: false
示例 2:
输入: 1->2->2->1
输出: true
进阶:
你能否用 O(n) 时间复杂度和 O(1) 空间复杂度解决此题?
思路:双指针
能想到是快慢指针,维持半条翻转链表,这不是简单的题目吧?
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {//执行用时 :1 ms, 在所有 Java 提交中击败了99.82%的用户
public boolean isPalindrome(ListNode head) {
if (head == null || head.next == null)
return true;
ListNode slow = head;
ListNode fast = head;
// 根据快慢指针,找到链表的中点
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
}
ListNode newHalf = reverse(slow);//翻转后半个链表
while(newHalf != null){// 两个半长链表的比较 遍历两个半长链表
if(head.val != newHalf.val){
return false;
}
newHalf = newHalf.next;
head = head.next;
}
return true;
}
private ListNode reverse(ListNode head) {
// 递归到最后一个节点,返回新的新的头结点
if (head.next == null) {
return head;
}
ListNode newHead = reverse(head.next);
head.next.next = head;
head.next = null;
return newHead;
}
}
283. 移动零简单
给定一个数组
nums
,编写一个函数将所有0
移动到数组的末尾,同时保持非零元素的相对顺序。
示例:
输入:[0,1,0,3,12]
,输出:[1,3,12,0,0]
说明:
- 必须在原数组上操作,不能拷贝额外的数组。
- 尽量减少操作次数。
思路:双指针
class Solution {//执行用时 :0 ms, 在所有 Java 提交中击败了100.00%的用户
public void moveZeroes(int[] nums) {
if(nums == null || nums.length < 1) {
return;
}
int j = 0;
//第一次遍历的时候,j用来记录当前有多少非0元素,把非0元素都向左移动
for(int i=0;i
287. 寻找重复数中等
给定一个包含 n + 1 个整数的数组
nums
,其数字都在 1 到 n 之间(包括 1 和 n),可知至少存在一个重复的整数。假设只有一个重复的整数,找出这个重复的数。
示例 1:
输入:[1,3,4,2,2]
输出: 2
示例 2:
输入: [3,1,3,4,2]
输出: 3
说明:
- 不能更改原数组(假设数组是只读的)。
- 只能使用额外的 O(1) 的空间。
- 时间复杂度小于 O(n2) 。
- 数组中只有一个重复的数字,但它可能不止重复出现一次。
思路:双指针二分查找
转自链接使用二分法查找一个有范围的整数(结合抽屉原理)https://leetcode-cn.com/problems/find-the-duplicate-number/solution/er-fen-fa-si-lu-ji-dai-ma-python-by-liweiwei1419/
class Solution {//执行用时 :3 ms, 在所有 Java 提交中击败了60.20%的用户
public int findDuplicate(int[] nums) {
if(nums == null || nums.length < 1)
return 0;
int left = 0;
int right = nums.length;
while(left < right){
int mid = (right - left) / 2 + left;
int count = 0;
for(int num:nums){
if(num <= mid){
count += 1;
}
}
if(count > mid){
right = mid;
}else{
left = mid + 1;
}
}
return left;
}
}
344. 反转字符串简单
编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组
char[]
的形式给出。
不要给另外的数组分配额外的空间,你必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题。
你可以假设数组中的所有字符都是 ASCII 码表中的可打印字符。
示例 1:
输入:["h","e","l","l","o"]
输出:["o","l","l","e","h"]
示例 2:
输入:["H","a","n","n","a","h"]
输出:["h","a","n","n","a","H"]
思路:双指针
设置两个首尾指针,互换元素,移动指针。
class Solution {//执行用时 :1 ms, 在所有 Java 提交中击败了99.96%的用户
public void reverseString(char[] s) {
if(s.length <= 0)
return;
int i = 0;
int j = s.length - 1;
while(i < j){
char temp = s[j];
s[j] = s[i];
s[i] = temp;
i++;
j--;
}
}
}
345. 反转字符串中的元音字母简单
编写一个函数,以字符串作为输入,反转该字符串中的元音字母。
示例 1:
输入: "hello",输出: "holle"
示例 2:
输入: "leetcode",输出: "leotcede"
说明:
元音字母不包含字母"y"。
思路:双指针
注意大小写都要包括。
class Solution {//执行用时 :6 ms, 在所有 Java 提交中击败了44.16%的用户
public String reverseVowels(String s) {
if(s.length() <= 1)
return s;
char[] c = s.toCharArray();
HashSet set = new HashSet<>(Arrays.asList('a', 'e', 'i', 'o', 'u', 'A', 'E', 'I', 'O', 'U'));
int i = 0;
int j = s.length() - 1;
while(i < j){
while(i < j && !set.contains(c[i])){
i++;
}
while(i < j && !set.contains(c[j])){
j--;
}
if(c[i] != c[j]){
char temp = c[j];
c[j] = c[i];
c[i] = temp;
}
i++;
j--;
}
return new String(c);
}
}
349. 两个数组的交集简单
给定两个数组,编写一个函数来计算它们的交集。
示例 :
输入: nums1 = [1,2,2,1], nums2 = [2,2],输出: [2]
思路:双指针
将两个数组排序,设置两个指针,分别从每个数组的第一个元素开始比较,移动指针,相等元素存入HashSet中,将set的元素写入一个新的数组中,并输出。
class Solution {//执行用时 :3 ms, 在所有 Java 提交中击败了98.09%的用户
public int[] intersection(int[] nums1, int[] nums2) {
if(nums1 == null || nums1.length < 0 || nums2 == null || nums2.length < 0)
return new int[0];
HashSet set = new HashSet<>();
Arrays.sort(nums1);
Arrays.sort(nums2);
int i = 0;
int j = 0;
while(i < nums1.length && j < nums2.length){
if(nums1[i] == nums2[j]){
set.add(nums1[i]);
i++;
j++;
}else if(nums1[i] < nums2[j]){
i++;
}else{
j++;
}
}
//将set的元素写入一个新的数组中
int[] res = new int[set.size()];
int index = 0;
for(int num:set){
res[index] = num;
index++;
}
return res;
}
}