数组:双指针法

LeetCode27. 移除元素

https://leetcode-cn.com/problems/remove-element/

给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。

不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组。

元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素

输入:nums = [3,2,2,3], val = 3
输出:2, nums = [2,2]
解释:函数应该返回新的长度 2, 并且 nums 中的前两个元素均为 2。你不需要考虑数组中超出新长度后面的元素。例如,函数返回的新长度为 2 ,而 nums = [2,2,3,3] 或 nums = [2,2,0,0],也会被视作正确答案。
思路

使用双指针法(快慢指针法):通过一个快指针和慢指针在一个for循环下完成两个for循环的工作。

删除过程如下:

转自代码随想录

代码
class Solution 
{
public:
    int removeElement(vector<int>& nums, int val) 
    {
        int sz = nums.size();

        int slowIndex = 0;
        for (int fastIndex = 0; fastIndex < sz; ++fastIndex)
        {
            if (nums[fastIndex] != val)
            {
                nums[slowIndex++] = nums[fastIndex];
            }
        }

        return slowIndex;
    }
};

LeetCode209. 长度最小的子数组

https://leetcode-cn.com/problems/minimum-size-subarray-sum/

给定一个含有 n 个正整数的数组和一个正整数 target 。

找出该数组中满足其和 ≥ target 的长度最小的 连续子数组 [numsl, numsl+1, …, numsr-1, numsr] ,并返回其长度。如果不存在符合条件的子数组,返回 0 。

输入:target = 7, nums = [2,3,1,2,4,3]
输出:2
解释:子数组 [4,3] 是该条件下的长度最小的子数组。
思路(暴力)

两个for循环,然后不断的寻找符合条件的子序列

代码
class Solution 
{
public:
    //暴力
    int minSubArrayLen(int s, vector<int>& nums) 
    {
        auto sz = nums.size();

        int result = INT_MAX;
        int subLength = 0;
        for (size_t i = 0; i != sz; ++i)
        {
            int sum = 0;
            for (size_t j = i; j != sz; ++j)
            {
                sum += nums[j];
                if (sum >= s)
                {
                    subLength = j - i + 1;
                    result = min(result, subLength);
                    break;
                }
            }
        }

        return result == INT_MAX ? 0 : result;
    }
}
思路(滑动窗口)

以题目中的示例来举例,s=7, 数组是 2,3,1,2,4,3,看一下查找的过程:

转自代码随想录
使用双指针法(滑动窗口)。

使用滑动窗口,主要确定如下三点:

  • 窗口内是什么?

    窗口就是 满足其和 ≥ s 的连续子数组。

  • 如何移动窗口的起始位置?

    如果当前窗口的值大于s了,窗口就要起始位置向前移动一格。

  • 如何移动窗口的结束位置?

    窗口的结束位置就是遍历数组的指针。

代码
class Solution 
{
public:
    //滑动窗口
    int minSubArrayLen(int s, vector<int>& nums)
    {
        auto sz = nums.size();

        int result = INT_MAX;
        int subLength = 0;
        size_t i = 0;
        int sum = 0;
        for (size_t j = 0; j != sz; ++j)
        {
            sum += nums[j];
            //以滑动窗口起始位置为起始位置的子数组已经遍历完毕,将滑动窗口起始位置向前移动一位
            //应使用while循环
            while (sum >= s)
            {
                subLength = j - i + 1;
                result = min(result, subLength);
                sum -= nums[i++];
            }
        }

        return result == INT_MAX ? 0 : result;
    }
};

LeetCode15. 三数之和

给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有和为 0 且不重复的三元组。

注意:答案中不可以包含重复的三元组。

输入:nums = [-1,0,1,2,-1,-4]
输出:[[-1,-1,2],[-1,0,1]]
思路

使用双指针法。

首先将数组排序,

然后使用一层for循环,i从下标0的地方开始,同时定一个left 定义在i+1的位置上,定义right 在sz - 1的位置上。在数组找到nums[i] + nums[left] + nums[right] == 0,(nums[i], nums[left], nums[right])构成符合条件的三元组。

接下来移动left 和right, 如果nums[i] + nums[left] + nums[right] > 0就说明此时三数之和大了(因为数组经过排序),所以right下表就应该向左移动,这样才能让三数之和小一些;如果 nums[i] + nums[left] + nums[right] < 0说明此时 三数之和小了,left 就向右移动,才能让三数之和大一些,直到left与right相遇为止。
图片

代码
class Solution 
{
public:
    vector<vector<int>> threeSum(vector<int>& nums) 
    {
        vector<vector<int>> result;
        int sz = nums.size();
        if (sz < 3)
        {
            return result;
        }

        sort(nums.begin(), nums.end());
        for (int i = 0; i < sz; ++i)
        {
            if (i >= 1 && nums[i] == nums[i - 1])
            {
                continue;
            }

            int left = i + 1, right = sz - 1;
            while (left < right)
            {
                if (nums[i] + nums[left] + nums[right] > 0)
                {
                    --right;
                }
                else if (nums[i] + nums[left] + nums[right] < 0)
                {
                    ++left;
                }
                else
                {
                    result.push_back({nums[i], nums[left], nums[right]});
                    //该去重逻辑应放在找到一个符合条件的三元组之后
                    while (left < right && nums[left] == nums[left + 1]) ++left;
                    while (left < right && nums[right] == nums[right - 1]) --right;
                    //找到答案时,双指针同时收缩
                    ++left;
                    --right;
                }
            }
        }

        return result;
    }
};

LeetCode18. 四数之和

给定一个包含 n 个整数的数组 nums 和一个目标值 target,判断 nums 中是否存在四个元素 a,b,c 和 d ,使得 a + b + c + d 的值与 target 相等?找出所有满足条件且不重复的四元组。

注意:答案中不可以包含重复的四元组。

输入:nums = [1,0,-1,0,-2,2], target = 0
输出:[[-2,-1,1,2],[-2,0,0,2],[-1,0,0,1]]
思路

使用双指针法。

与LeetCode15. 三数之和相似,四数之和的双指针解法是使用两层for循环nums[i] + nums[j]为确定值,依然是循环内有left = j + 1和right = sz - 1作为双指针,找出nums[k] + nums[i] + nums[left] + nums[right] == target的四元组。

代码
class Solution 
{
public:
    vector<vector<int>> fourSum(vector<int>& nums, int target) 
    {
        vector<vector<int>> result;
        auto sz = nums.size();
        if (sz < 4) return result;

        sort(nums.begin(), nums.end());
        for (size_t i = 0; i != sz; ++i)
        {
            if (i >= 1 && nums[i] == nums[i - 1])
            {
                continue;
            }

            for (size_t j = i + 1; j != sz; ++j)
            {
                if (j >= i + 2 && nums[j] == nums[j - 1])
                {
                    continue;
                }

                size_t left = j + 1, right = sz - 1;
                while (left < right)
                {
                    if (nums[i] + nums[j] + nums[left] + nums[right] < target)
                    {
                        ++left;
                    }
                    else if (nums[i] + nums[j] + nums[left] + nums[right] > target)
                    {
                        --right;
                    }
                    else
                    {
                        result.push_back(vector<int>{nums[i], nums[j], nums[left], nums[right]});
                        while (left < right && nums[left] == nums[left + 1]) ++left;
                        while (left < right && nums[right] == nums[right - 1]) --right;
                        ++left;
                        --right;
                    }
                }
            }
        }
        
        return result;
    }
};
LeetCode59. 螺旋矩阵II

给你一个正整数 n ,生成一个包含 1n2 所有元素,且元素按顺时针顺序螺旋排列的 n x n 正方形矩阵 matrix

在这里插入图片描述

输入:n = 3
输出:[[1,2,3],[8,9,4],[7,6,5]]
思路

本题就是一个模拟过程,关键在于保持区间形式一致,我采用左闭右开的区间形式。

模拟顺时针画矩阵的过程:

  • 填充上行从左到右
  • 填充右列从上到下
  • 填充下行从右到左
  • 填充左列从下到上

由外向内一圈一圈这么画下去。

照左闭右开的区间形式,来画一圈:

在这里插入图片描述

代码
class Solution 
{
public:
    vector<vector<int>> generateMatrix(int n) 
    {
        vector<vector<int>> result(n, vector<int>(n, 0));

        int loop = n / 2;      //画圈的次数,例如:若n = 3,则画圈一次,中间一个数字单独处理;若n = 4,则画圈两次
        int startx = 0, starty = 0;    //遍历的横纵坐标起点
        int offset = 1;        //用于控制每次画圈每一条边的长度
        int count = 1;         //遍历填充的数字

        while (loop--)
        {
            int i = startx, j = starty;

            //四边,左闭右开
            //从左到右
            for (j = starty; j < starty + n - offset; ++j)
            {
                result[startx][j] = count++;
            }

            //从上到下
            for (i = startx; i < startx + n - offset; ++i)
            {
                result[i][j] = count++;
            }

            //从右到左
            for (; j > starty; --j)
            {
                result[i][j] = count++;
            }

            //从下到上
            for (; i > startx; --i)
            {
                result[i][j] = count++;
            }

            //横纵坐标加1
            ++startx;
            ++starty;

            offset += 2;
        }
        
        //奇数,正中心单独处理
        if (n % 2)
        {
            result[n / 2][n / 2] = n * n;
        }

        return result;
    }
};
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值