双指针在数组遍历中的应用

简介: 文章深入探讨了双指针技术在数组遍历中的应用,通过实战例子详细解释了快慢指针和首尾指针的不同用法,并提供了解决LeetCode相关问题的Java代码实现。

算法是计算机软件的基础,今年打算深入学习一些算法,记录一些算法理论以及最佳实践,希望可以坚持下去。

截屏2024-01-11 23.09.34.png

一、前言

数组是最基础的数据结构之一,数组遍历是基本功,本文目的是深入学习双指针法来对数组遍历以及双指针遍历数组算法的实战。

二、双指针介绍

我们一般遍历数组使用一个下标从前往后遍历就可以实现遍历完数组,这整个过程只需要一个下标

截屏2024-01-11 23.26.00.png

那么双指针是怎么样呢? 其实就是使用两个下标对数组进行遍历。

截屏2024-01-11 23.30.31.png

为什么需要双指针呢? 主要为了弥补一些通过单指针遍历数组解决不了的场景。

比如原地移除数组元素。 下面例子需要原地移除元素里的9,通过双指针可以解决,快指针遍历数组元素值,慢指针记录需要留下的元素。但是单指针解决就麻烦。

截屏2024-01-11 23.34.10.png

再比如反转字符串,我们可以通过首尾双指针,通过两个指针同时往中间遍历,交换元素值实现反转功能。

截屏2024-01-11 23.43.00.png

因此双指针有两种类型,一种是前后双指针也可以叫做快慢双指针,一种是首尾双指针

快慢双指针用来从前往后遍历数组。

首尾双指针用来由两端往中间遍历数组。

三、双指针实战

罗列下部分可以通过双指针解决的leetcode题目:

27. 移除元素

344. 反转字符串

151.翻转字符串里的单词

第15题. 三数之和

977.有序数组的平方

本文分析下有序数组的平方

截屏2024-01-11 23.57.01.png

我们可以借助首尾双指针解决此题,因为平方后的数一定在两端。这样我们可以遍历最大,次最大,次次最大,最后是平方值最小的。以此类推。

截屏2024-01-11 23.59.49.png

class Solution {
   
   
    public int[] sortedSquares(int[] nums) {
   
   

        int start = 0; //首指针
        int end = nums.length-1; //尾指针

        int[] result = new int[nums.length];
        int index = nums.length - 1;

        while(start <= end) {
   
   
            if(nums[start] * nums[start] > nums[end] * nums[end]) {
   
   
                result[index--] = nums[start] * nums[start];
                start++;
            } else {
   
   
                result[index--] = nums[end] * nums[end];
                end--;
            }
        }

        return result;

    }
}

leetcode18. 四数之和

class Solution {
   
   
    public List<List<Integer>> fourSum(int[] nums, int target) {
   
   

        List<List<Integer>> result = new ArrayList<>();
        Arrays.sort(nums);
        for(int i=0; i<nums.length; i++) {
   
   

            int a = nums[i];

            if (nums[i] > 0 && nums[i] > target) {
   
   
                return result;
            }

            //需要去重a 2 2 2 2 2 不能用while 死循环了
            if(i > 0 && nums[i-1] == nums[i]) {
   
   
                continue;
            }

            for(int j = i+1; j<nums.length; j++) {
   
   

                int b = nums[j];

                //需要去重b
                if(j > i+1 && nums[j-1] == nums[j]) {
   
   
                    continue;
                }

                int left = j+1;
                int right = nums.length-1;

                //System.out.println(k+"==="+l);

                while(right>left) {
   
   

                    int c = nums[left];
                    int d = nums[right];

                    long sum = (long) nums[i] + nums[j] + nums[left] + nums[right];

                    if(sum == target) {
   
   
                        List<Integer> subResult = new ArrayList<>();
                        subResult.add(a);
                        subResult.add(b);
                        subResult.add(c);
                        subResult.add(d);
                        result.add(subResult);

                        System.out.println(a+"="+b+"="+c+"="+d);

                        while(right>left && nums[right-1] == nums[right]) {
   
   
                            right--;
                        }

                        while(right>left && nums[left+1] == nums[left]) {
   
   
                            left++;
                        }

                        left++;
                        right--;

                    } else if(sum > target) {
   
   
                         right--; 
                         //System.out.println(k+"="+l);  
                    } else if(sum < target) {
   
   
                         left++;
                    }
                }
            }

        }

        return result;

    }
}

四数之和这道题通过双指针法从两端往中间来遍历c,d两个元素。

15. 三数之和

class Solution {
   
   
    //思路 定义一个固定节点 两个起始节点 移动起始节点确定有没有等于0的情况
    public List<List<Integer>> threeSum(int[] nums) {
   
   

        int size = nums.length;
        Arrays.sort(nums);
        List<List<Integer>> result = new ArrayList<>();
        for(int i =0; i<size; i++) {
   
   

            if(nums[i] >0) {
   
   
                return result;
            }
            //去重
            if(i>0 && nums[i] == nums[i-1]) {
   
   
                continue;
            }

            int start = i+1;
            int end = size-1;

            while(start < end) {
   
   

                int r = (nums[start] + nums[end] + nums[i]);
                if(r == 0) {
   
   
                    //找到了符合和等于0的,记录下来
                    List<Integer> subResult = new ArrayList<>();
                    subResult.add(nums[i]);
                    subResult.add(nums[start]);
                    subResult.add(nums[end]);
                    result.add(subResult);
                    //去重复
                    while(start< end && nums[start] == nums[start+1]) {
   
   
                        start = start +1;
                    }
                    //去除重复
                    while(start < end && nums[end] == nums[end-1]) {
   
   
                        end = end-1;
                    }
                    start++;
                    end--;
                    continue;
                } 
                //和大于0,右边的数太大,因此右边的索引要往左移
                if( r > 0) {
   
   
                    end--;
                    continue;
                }
                //和小于0,左边的数太小,因此左边的索引往右移
                if( r < 0) {
   
   
                   start++;
                }
            }
        }
        return result;
    }
}

三数之和和四数之和是一样的技巧,通过从两端往中间遍历确定b,d的值。

四、总结

本文主要分析了有两种双指针形态,首尾指针快慢指针。双指针遍历数组可以提高遍历数组算法性能提升。

把双指针算法常见形态和场景记录下来,我相信有输入就需要有输出,希望对以后的编码有帮助。

关注我一起学习算法技巧吧。

相关文章
|
4天前
|
存储
如何使用指针数组来实现动态二维数组
指针数组可以用来实现动态二维数组。首先,定义一个指向指针的指针变量,并使用 `malloc` 为它分配内存,然后为每个子数组分配内存。通过这种方式,可以灵活地创建和管理不同大小的二维数组。
|
4天前
|
存储
如何通过指针数组来实现二维数组?
介绍了二维数组和指针数组的概念及其区别,详细讲解了如何使用指针数组模拟二维数组,包括定义与分配内存、访问和赋值元素、以及正确释放内存的步骤,适用于需要动态处理二维数据的场景。
|
4天前
|
存储 算法 C语言
C语言:什么是指针数组,它有什么用
指针数组是C语言中一种特殊的数据结构,每个元素都是一个指针。它用于存储多个内存地址,方便对多个变量或数组进行操作,常用于字符串处理、动态内存分配等场景。
|
10天前
魔法指针 之 二级指针 指针数组
魔法指针 之 二级指针 指针数组
13 1
|
1月前
|
传感器 物联网 大数据
C 指针在物联网的应用
在物联网(IoT)中,C 语言及其指针功能广泛应用于嵌入式系统。C 指针在内存管理、设备驱动、数据结构处理、传感器通信等方面发挥关键作用,如动态分配内存、直接访问硬件寄存器、传递复杂数据结构等,有效提升了资源受限环境下的性能和灵活性。通过函数指针和省电模式管理,还能实现事件驱动编程和节能目标,使 C 语言成为 IoT 开发的重要工具。
60 12
|
13天前
|
存储
一篇文章了解区分指针数组,数组指针,函数指针,链表。
一篇文章了解区分指针数组,数组指针,函数指针,链表。
15 0
|
19天前
|
编译器 C语言
【C语言】指针篇-深入探索数组名和指针数组- 必读指南(2/5)
【C语言】指针篇-深入探索数组名和指针数组- 必读指南(2/5)
|
1月前
|
存储 安全 C语言
C语言 二级指针应用场景
本文介绍了二级指针在 C 语言中的应用,
|
2月前
|
搜索推荐 C语言
指针与数组
指针与数组
54 9
|
2月前
|
存储 程序员 C语言
指针的高级应用:指针数组、数组指针、函数指针等。
指针的高级应用:指针数组、数组指针、函数指针等。
93 0