python 双指针_3.双指针(三)

本文详细介绍双指针算法的应用场景及其实现方法,通过多个示例深入浅出地讲解了双指针如何高效解决问题,如寻找两数之和、最小连续子数组长度、回文链表验证等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

给定一个已按照升序排列的有序数组,找到两个数使得它们相加之和等于目标数。

函数应该返回这两个下标值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;

}

}

给定一个含有 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

sum += nums[right];//扩大区间

while(sum >= s){

min = Math.min(min, right - left + 1);

sum -= nums[left++];//减小区间

}

}

return min == Integer.MAX_VALUE ? 0 : min;

}

}

请判断一个链表是否为回文链表。

示例 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;

}

}

给定一个数组 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

if(nums[i]!=0) {

nums[j] = nums[i];

j++;

}

}

//第二次遍历把末尾的元素都赋为0

for(int i=j;i

nums[i] = 0;

}

}

}

给定一个包含 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) 。

数组中只有一个重复的数字,但它可能不止重复出现一次。

思路:双指针二分查找

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;

}

}

编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 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--;

}

}

}

编写一个函数,以字符串作为输入,反转该字符串中的元音字母。

示例 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);

}

}

给定两个数组,编写一个函数来计算它们的交集。

示例 :

输入: 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;

}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值