双指针技巧总结

2023-11-17

一、双指针技巧——情景1

  通常,我们只需要一个指针进行迭代,即从数组中的第一个元素开始,最后一个元素结束。然而,有时我们会使用两个指针进行迭代。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
双指针的典型场景
(1)从两端向中间迭代数组。
(2)一个指针从头部开始,而另一个指针从尾部开始。

1.反转字符串

在这里插入图片描述

解法:双指针

在这里插入图片描述
在这里插入图片描述
c

void swap(char *a, char *b) {
    char t = *a;
    *a = *b, *b = t;
}

void reverseString(char *s, int sSize) {
    for (int left = 0, right = sSize - 1; left < right; ++left, --right) {
        swap(s + left, s + right);
    }
}

c++

class Solution {
public:
    void reverseString(vector<char>& s) {
        int n = s.size();
        for (int left = 0, right = n - 1; left < right; ++left, --right) {
            swap(s[left], s[right]);
        }
    }
};

2.数组拆分

在这里插入图片描述

解法:排序

在这里插入图片描述
在这里插入图片描述
C

int cmp(int *a, int *b) {
    return *a - *b;
}

int arrayPairSum(int *nums, int numsSize) {
    qsort(nums, numsSize, sizeof(int), cmp);
    int ans = 0;
    for (int i = 0; i < numsSize; i += 2) {
        ans += nums[i];
    }
    return ans;
}

解析:
1.qsort函数
qsort是C语言标准库中用于对数组进行快速排序的函数。它的函数原型如下:

void qsort(void *base, size_t nitems, size_t size, int (*compar)(const void *, const void*));

qsort函数的第一个参数是需要排序的数组的指针base,第二个参数是数组的元素个数nitems,第三个参数是每个元素的大小size(以字节为单位),第四个参数是一个指向比较函数的指针compar。

比较函数compar接受两个指向待比较元素的指针,并返回一个整数值,表示它们的大小关系。如果第一个元素小于第二个元素,则返回一个负数;如果它们相等,则返回0;如果第一个元素大于第二个元素,则返回一个正数。这个函数的原型如下:

int (*compar)(const void *, const void*)

C++

class Solution {
public:
    int arrayPairSum(vector<int>& nums) {
        sort(nums.begin(), nums.end());
        int ans = 0;
        for (int i = 0; i < nums.size(); i += 2) {
            ans += nums[i];
        }
        return ans;
    }
};

3.两数之和(输入有序数组)

在这里插入图片描述

方法1:二分法查找

在这里插入图片描述

c

int* twoSum(int* numbers, int numbersSize, int target, int* returnSize) {
    int* ret = (int*)malloc(sizeof(int) * 2);
    *returnSize = 2;

    for (int i = 0; i < numbersSize; ++i) {
        int low = i + 1, high = numbersSize - 1;
        while (low <= high) {
            int mid = (high - low) / 2 + low;
            if (numbers[mid] == target - numbers[i]) {
                ret[0] = i + 1, ret[1] = mid + 1;
                return ret;
            } else if (numbers[mid] > target - numbers[i]) {
                high = mid - 1;
            } else {
                low = mid + 1;
            }
        }
    }
    ret[0] = -1, ret[1] = -1;
    return ret;
}

解释:
函数 twoSum 接受四个参数:
numbers:一个指向整数数组开头的指针
numbersSize:表示 numbers 数组的大小的整数
target:目标整数
returnSize:一个指向整数的指针,用于返回结果数组的大小

c++

class Solution {
public:
    vector<int> twoSum(vector<int>& numbers, int target) {
        for (int i = 0; i < numbers.size(); ++i) {
            int low = i + 1, high = numbers.size() - 1;
            while (low <= high) {
                int mid = (high - low) / 2 + low;
                if (numbers[mid] == target - numbers[i]) {
                    return {i + 1, mid + 1};
                } else if (numbers[mid] > target - numbers[i]) {
                    high = mid - 1;
                } else {
                    low = mid + 1;
                }
            }
        }
        return {-1, -1};
    }
};

方法2:双指针

在这里插入图片描述
c

int* twoSum(int* numbers, int numbersSize, int target, int* returnSize) {
    int* ret = (int*)malloc(sizeof(int) * 2);
    *returnSize = 2;

    int low = 0, high = numbersSize - 1;
    while (low < high) {
        int sum = numbers[low] + numbers[high];
        if (sum == target) {
            ret[0] = low + 1, ret[1] = high + 1;
            return ret;
        } else if (sum < target) {
            ++low;
        } else {
            --high;
        }
    }
    ret[0] = -1, ret[1] = -1;
    return ret;
}

c++

class Solution {
public:
    vector<int> twoSum(vector<int>& numbers, int target) {
        int low = 0, high = numbers.size() - 1;
        while (low < high) {
            int sum = numbers[low] + numbers[high];
            if (sum == target) {
                return {low + 1, high + 1};
            } else if (sum < target) {
                ++low;
            } else {
                --high;
            }
        }
        return {-1, -1};
    }
};

二、双指针技巧——情景2

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

1.移除元素

在这里插入图片描述
在这里插入图片描述

方法1:双指针

在这里插入图片描述
c

int removeElement(int* nums, int numsSize, int val) {
    int left = 0;
    for (int right = 0; right < numsSize; right++) {
        if (nums[right] != val) {
            nums[left] = nums[right];
            left++;
        }
    }
    return left;
}

c++

class Solution {
public:
    int removeElement(vector<int>& nums, int val) {
        int n = nums.size();
        int left = 0;
        for (int right = 0; right < n; right++) {
            if (nums[right] != val) {
                nums[left] = nums[right];
                left++;
            }
        }
        return left;
    }
};

方法2:双指针优化

在这里插入图片描述
c

int removeElement(int* nums, int numsSize, int val) {
    int left = 0, right = numsSize;
    while (left < right) {
        if (nums[left] == val) {
            nums[left] = nums[right - 1];
            right--;
        } else {
            left++;
        }
    }
    return left;
}

c++

class Solution {
public:
    int removeElement(vector<int>& nums, int val) {
        int left = 0, right = nums.size();
        while (left < right) {
            if (nums[left] == val) {
                nums[left] = nums[right - 1];
                right--;
            } else {
                left++;
            }
        }
        return left;
    }
};

2.最大连续1的个数

在这里插入图片描述

方法1:一次遍历

在这里插入图片描述
c

int findMaxConsecutiveOnes(int* nums, int numsSize) {
    int maxCount = 0, count = 0;
    for (int i = 0; i < numsSize; i++) {
        if (nums[i] == 1) {
            count++;
        } else {
            maxCount = fmax(maxCount, count);
            count = 0;
        }
    }
    maxCount = fmax(maxCount, count);
    return maxCount;
}

c++

class Solution {
public:
    int findMaxConsecutiveOnes(vector<int>& nums) {
        int maxCount = 0, count = 0;
        int n = nums.size();
        for (int i = 0; i < n; i++) {
            if (nums[i] == 1) {
                count++;
            } else {
                maxCount = max(maxCount, count);
                count = 0;
            }
        }
        maxCount = max(maxCount, count);
        return maxCount;
    }
};

3.长度最小的子数组

在这里插入图片描述

方法1:暴力法

在这里插入图片描述
c

int minSubArrayLen(int s, int* nums, int numsSize) {
    if (numsSize == 0) {
        return 0;
    }
    int ans = INT_MAX;
    for (int i = 0; i < numsSize; i++) {
        int sum = 0;
        for (int j = i; j < numsSize; j++) {
            sum += nums[j];
            if (sum >= s) {
                ans = fmin(ans, j - i + 1);
                break;
            }
        }
    }
    return ans == INT_MAX ? 0 : ans;
}

C++

class Solution {
public:
    int minSubArrayLen(int s, vector<int>& nums) {
        int n = nums.size();
        if (n == 0) {
            return 0;
        }
        int ans = INT_MAX;
        for (int i = 0; i < n; i++) {
            int sum = 0;
            for (int j = i; j < n; j++) {
                sum += nums[j];
                if (sum >= s) {
                    ans = min(ans, j - i + 1);
                    break;
                }
            }
        }
        return ans == INT_MAX ? 0 : ans;
    }
};

方法2:前缀和+二分查找

在这里插入图片描述
c

int lower_bound(int *a, int l, int r, int q) {
    if (a[r] < q) return -1;
    while (l < r) {
        int mid = (l + r) >> 1;
        if (a[mid] >= q) {
            r = mid;
        } else {
            l = mid + 1;
        }
    }
    return l;
}
int minSubArrayLen(int s, int *nums, int numsSize) {
    if (numsSize == 0) {
        return 0;
    }
    int ans = INT_MAX;
    int *sums = (int *)malloc(sizeof(int) * (numsSize + 1));
    // 为了方便计算,令 size = n + 1
    // sums[0] = 0 意味着前 0 个元素的前缀和为 0
    // sums[1] = A[0] 前 1 个元素的前缀和为 A[0]
    // 以此类推
    for (int i = 1; i <= numsSize; i++) {
        sums[i] = sums[i - 1] + nums[i - 1];
    }
    for (int i = 1; i <= numsSize; i++) {
        int target = s + sums[i - 1];
        int bound = lower_bound(sums, 1, numsSize, target);
        if (bound != -1) {
            ans = fmin(ans, bound - (i - 1));
        }
    }
    return ans == INT_MAX ? 0 : ans;
}

C++

class Solution {
public:
    int minSubArrayLen(int s, vector<int>& nums) {
        int n = nums.size();
        if (n == 0) {
            return 0;
        }
        int ans = INT_MAX;
        vector<int> sums(n + 1, 0); 
        // 为了方便计算,令 size = n + 1 
        // sums[0] = 0 意味着前 0 个元素的前缀和为 0
        // sums[1] = A[0] 前 1 个元素的前缀和为 A[0]
        // 以此类推
        for (int i = 1; i <= n; i++) {
            sums[i] = sums[i - 1] + nums[i - 1];
        }
        for (int i = 1; i <= n; i++) {
            int target = s + sums[i - 1];
            auto bound = lower_bound(sums.begin(), sums.end(), target);
            if (bound != sums.end()) {
                ans = min(ans, static_cast<int>((bound - sums.begin()) - (i - 1)));
            }
        }
        return ans == INT_MAX ? 0 : ans;
    }
};

方法3:滑动窗口

在这里插入图片描述
c

int minSubArrayLen(int s, int *nums, int numsSize) {
    if (numsSize == 0) {
        return 0;
    }
    int ans = INT_MAX;
    int start = 0, end = 0;
    int sum = 0;
    while (end < numsSize) {
        sum += nums[end];
        while (sum >= s) {
            ans = fmin(ans, end - start + 1);
            sum -= nums[start];
            start++;
        }
        end++;
    }
    return ans == INT_MAX ? 0 : ans;
}

C++

class Solution {
public:
    int minSubArrayLen(int s, vector<int>& nums) {
        int n = nums.size();
        if (n == 0) {
            return 0;
        }
        int ans = INT_MAX;
        int start = 0, end = 0;
        int sum = 0;
        while (end < n) {
            sum += nums[end];
            while (sum >= s) {
                ans = min(ans, end - start + 1);
                sum -= nums[start];
                start++;
            }
            end++;
        }
        return ans == INT_MAX ? 0 : ans;
    }
};
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

双指针技巧总结 的相关文章

  • 结构化绑定中缺少类型信息

    我刚刚了解了 C 中的结构化绑定 但有一件事我不喜欢 auto x y some func is that auto正在隐藏类型x and y 我得抬头看看some func的声明来了解类型x and y 或者 我可以写 T1 x T2 y
  • 没有特殊字符的密码验证器

    我是 RegEx 的新手 已经进行了大量搜索 但没有找到任何具体内容 我正在编写一个验证密码字符串的正则表达式 可接受的字符串必须至少具有 4 种字符类型中的 3 种 数字 小写字母 大写字母 特殊字符 我对包含有一个想法 也就是说 如果这
  • 在一个数据访问层中处理多个连接字符串

    我有一个有趣的困境 我目前有一个数据访问层 它必须与多个域一起使用 并且每个域都有多个数据库存储库 具体取决于所调用的存储过程 目前 我只需使用 SWITCH 语句来确定应用程序正在运行的计算机 并从 Web config 返回适当的连接字
  • C++11 删除重写方法

    Preface 这是一个关于最佳实践的问题 涉及 C 11 中引入的删除运算符的新含义 当应用于覆盖继承父类的虚拟方法的子类时 背景 根据标准 引用的第一个用例是明确禁止调用某些类型的函数 否则转换将是隐式的 例如最新版本第 8 4 3 节
  • 如何从本机 C(++) DLL 调用 .NET (C#) 代码?

    我有一个 C app exe 和一个 C my dll my dll NET 项目链接到本机 C DLL mynat dll 外部 C DLL 接口 并且从 C 调用 C DLL 可以正常工作 通过使用 DllImport mynat dl
  • -webkit-box-shadow 与 QtWebKit 模糊?

    当时有什么方法可以实现 webkit box shadow 的工作模糊吗 看完这篇评论错误报告 https bugs webkit org show bug cgi id 23291 我认识到这仍然是一个问题 尽管错误报告被标记为RESOL
  • 无限循环与无限递归。两者都是未定义的吗?

    无副作用的无限循环是未定义的行为 看here https coliru stacked crooked com view id 24e0a58778f67cd4举个例子参考参数 https en cppreference com w cpp
  • 需要帮助优化算法 - 两百万以下所有素数的总和

    我正在尝试做一个欧拉计划 http projecteuler net问题 我正在寻找 2 000 000 以下所有素数的总和 这就是我所拥有的 int main int argc char argv unsigned long int su
  • 访问外部窗口句柄

    我当前正在处理的程序有问题 这是由于 vista Windows 7 中增强的安全性引起的 特别是 UIPI 它阻止完整性级别较低的窗口与较高完整性级别的窗口 对话 就我而言 我想告诉具有高完整性级别的窗口进入我们的应用程序 它在 XP 或
  • 人脸 API DetectAsync 错误

    我想创建一个简单的程序来使用 Microsoft Azure Face API 和 Visual Studio 2015 检测人脸 遵循 https social technet microsoft com wiki contents ar
  • WcfSvcHost 的跨域异常

    对于另一个跨域问题 我深表歉意 我一整天都在与这个问题作斗争 现在已经到了沸腾的地步 我有一个 Silverlight 应用程序项目 SLApp1 一个用于托管 Silverlight SLApp1 Web 的 Web 项目和 WCF 项目
  • C# - 当代表执行异步任务时,我仍然需要 System.Threading 吗?

    由于我可以使用委托执行异步操作 我怀疑在我的应用程序中使用 System Threading 的机会很小 是否存在我无法避免 System Threading 的基本情况 只是我正处于学习阶段 例子 class Program public
  • 复制目录下所有文件

    如何将一个目录中的所有内容复制到另一个目录而不循环遍历每个文件 你不能 两者都不Directory http msdn microsoft com en us library system io directory aspx nor Dir
  • 为什么 isnormal() 说一个值是正常的,而实际上不是?

    include
  • 如何在 Android 中使用 C# 生成的 RSA 公钥?

    我想在无法假定 HTTPS 可用的情况下确保 Android 应用程序和 C ASP NET 服务器之间的消息隐私 我想使用 RSA 来加密 Android 设备首次联系服务器时传输的对称密钥 RSA密钥对已在服务器上生成 私钥保存在服务器
  • 相当于Linux中的导入库

    在 Windows C 中 当您想要链接 DLL 时 您必须提供导入库 但是在 GNU 构建系统中 当您想要链接 so 文件 相当于 dll 时 您就不需要链接 为什么是这样 是否有等效的 Windows 导入库 注意 我不会谈论在 Win
  • C# 中的 IPC 机制 - 用法和最佳实践

    不久前我在 Win32 代码中使用了 IPC 临界区 事件和信号量 NET环境下场景如何 是否有任何教程解释所有可用选项以及何时使用以及为什么 微软最近在IPC方面的东西是Windows 通信基础 http en wikipedia org
  • 当文件流没有新数据时如何防止fgets阻塞

    我有一个popen 执行的函数tail f sometextfile 只要文件流中有数据显然我就可以通过fgets 现在 如果没有新数据来自尾部 fgets 挂起 我试过ferror and feof 无济于事 我怎样才能确定fgets 当
  • 在OpenGL中,我可以在坐标(5, 5)处精确地绘制一个像素吗?

    我所说的 5 5 正是指第五行第五列 我发现使用屏幕坐标来绘制东西非常困难 OpenGL 中的所有坐标都是相对的 通常范围从 1 0 到 1 0 为什么阻止程序员使用屏幕坐标 窗口坐标如此严重 最简单的方法可能是通过以下方式设置投影以匹配渲
  • Mono 应用程序在非阻塞套接字发送时冻结

    我在 debian 9 上的 mono 下运行一个服务器应用程序 大约有 1000 2000 个客户端连接 并且应用程序经常冻结 CPU 使用率达到 100 我执行 kill QUIT pid 来获取线程堆栈转储 但它总是卡在这个位置

随机推荐

  • sql注入语句万能密码_sql注入——万能密码

    通过两个ctf题来做讲解 第一个很简单 第二个多了些限制 http lab1 xseclab com sqli2 3265b4852c13383560327d1c31550b60 index php http ctf5 shiyanbar
  • centos7安装k8s 1.24.3版本 Error getting node“ err=“node “master01“ not found

    简介 kubernetes 1 24 0以上版本已经移除了docker cri 因此在使用的docker来的安装k8s时 你需要自己安装cri docker 名词解释 cri 容器运行时 这个东东是用来在pod中控制容器的 服务器最低配置要
  • (c语言)写一个宏,实现offsetof,实现整数二进制奇偶位交换

    目录 1 写一个宏实现offsetof 1 1 offsetof是什么 1 2 模拟实现offsetof 1 思路 2 代码 2 写一个宏实现整数二进制奇偶位交换 思路 代码 总结 1 写一个宏实现offsetof 1 1 offsetof
  • Android 内存泄漏的常见原因及其对应的解决方案

    Android 内存泄漏 Android应用程序中常见的内存泄漏原因有很多 以下是一些常见的原因及对应的解决方案 1 静态引用导致的内存泄漏 静态变量持有对Activity或Fragment的引用 导致它们无法被垃圾回收机制释放 解决方案
  • LogisticRegression

    1 概述 在scikit learn中 与逻辑回归有关的主要是这3个类 LogisticRegression LogisticRegressionCV 和logistic regression path 其中LogisticRegressi
  • 11个优秀的Android开发开源项目

    一 一个类似微信的时光轴效果 项目地址 https github com ljtyzhr TimeLine 二 安卓选择器类库 包括日期 时间 单项 双项选择器 城市地址选择器 项目地址 https github com gzu liyuj
  • hbase hbck工具

    fix Try to fix region assignments This is for backwards compatiblity fixAssignments Try to fix region assignments Replac
  • 网络视频刷单调查:4分钟免费刷2.2万300元能买4000万点击

    新生事物的起步常伴随着混沌期的野蛮生长 比如网络视频行业 如果说票房测量电影市场的高低 收视率检验电市场的冷暖 那么反映网络视频是否受欢迎的一个直观指标就是点击量了 公众所看到的视频点击量数据真实性到底如何 又有多少点击量是靠 刷单 刷出来
  • 掌握Python的X篇_23_main的作用(python规范写代码中,__name__内置变量的使用)

    上篇我们介绍了模块和如何使用模块 本篇将会介绍与模块共同会出现的问题 那就是在python规范写代码中会使用到 name 这种特殊的变量 文章目录 1 name 是什么 2 模块import的不方便 3 name 的用处 大家可能已经见过
  • 聚焦Web前端安全:最新揭秘漏洞防御方法

    在 Web 安全中 服务端一直扮演着十分重要的角色 然而前端的问题也不容小觑 它也会导致信息泄露等诸如此类的问题 在这篇文章中 我们将向读者介绍如何防范Web前端中的各种漏洞 万字长文 请先收藏再阅读 首先 我们需要了解安全防御产品已经为我
  • 【StyleGAN论文精读CVPR_2019】A Style-Based Generator Architecture for Generative Adversarial Networks

    StyleGAN论文精读CVPR 2019 A Style Based Generator Architecture for Generative Adversarial Networks 一 前言 Abstract 1 Introduct
  • 6-5抽象类和抽象方法的使用

    package com atguigu java abstract 关键字的使用 1 abstract 抽象的 2 abstract 可以用来修饰的结构 类 方法 3 abstract 修饰类 抽象类 此类不能实例化 抽象类中一定有构造器便
  • Makefile学习3

    addprefix函数 函数名称 加前缀函数 addprefix 返回值 以单空格分割的添加了前缀 PREFIX 的文件名序列 示例 addprefix src foo bar 回值为 src foo src bar wildcard即通配
  • 【网络协议详解】——数据链路层协议(学习笔记)

    前言 数据链路层是 OSI 模型中的第二层 位于物理层之上 是通信网络中的重要组成部分之一 数据链路层协议负责将网络层传输的数据分组封装成帧 传输到物理层 并通过物理介质进行传输 同时 数据链路层协议还需要提供错误检测和纠正 流控等功能 以
  • Android 使用高德SDK编写周边搜索定位

    转载请注明 前言 使用高德SDK实现定位及周边的搜索界面 先看效果图 效果图看这 传不上 使用到了高德以下sdk com amap api 3dmap latest integration com amap api search lates
  • 解决IDEA导入MAVEN项目,jar包没有引进来报Cannot resolve symbol 'Autowired'

    解决IDEA导入MAVEN项目 jar包没有引进来报Cannot resolve symbol Autowired 原因 IDEA的缓存导致 解决办法 找到项目所在文件夹 找到 idea文件夹 删掉 从新导入 就好了
  • Web后端开发(请求响应)上

    请求响应的概述 浏览器 请求 lt HTTP协议 gt 响应 Web服务器 请求 获取请求数据 响应 设置响应数据 BS架构 浏览器 服务器架构模式 客户端只需要浏览器 应用程序的逻辑和数据都存储在服务端 维护方便 体验一般 CS架构 客户
  • Navicat15工具连接PostgreSQL15失败

    1 错误现象及原因 错误现象 错误原因 postgresql 15版本中 pg database 系统表把 datlastsysoid 列删除了 所以造成了此错误 2 解决方法 1 将Navicat工具更新到官网最新版本 2 更换 post
  • uboot SPL framework的前世今生

    一开始只有uboot 没有SPL 后来由于一些原因 参考文献1 有些公司如TI添加了SPL 模块 SPL的作用为 参考文献2 为了提高代码的可重用性 uboot 2012 10中将SPL模块标准化 叫做SPL framework 查看ubo
  • 双指针技巧总结

    一 双指针技巧 情景1 通常 我们只需要一个指针进行迭代 即从数组中的第一个元素开始 最后一个元素结束 然而 有时我们会使用两个指针进行迭代 双指针的典型场景 1 从两端向中间迭代数组 2 一个指针从头部开始 而另一个指针从尾部开始 1 反