【C++刷题】优选算法——双指针

  1. 移动零
cpp 复制代码
void moveZeroes(vector<int>& nums)
{
    size_t  front = 0;
    size_t back = 0;
    while(back < nums.size() && nums[back] != 0)
    {
        ++back;
    }
    front = back++;
    while(back < nums.size())
    {
        if(0 == nums[back])
        {
            ++back;
        }
        else
        {
            swap(nums[front++], nums[back++]);     
        }
    }
}
  1. 复写零
    先找到最后一个被"复写"的数,然后从后向前完成"复写"操作。同时要注意处理一下边界情况。
cpp 复制代码
void duplicateZeros(vector<int>& arr)
{
    int front = 0;
    int back = -1;
    while(true)
    {
        if(0 == arr[front])
        {
            back += 2;
        }
        else
        {
            back += 1;
        }
        if(back == arr.size())
        {
            --back;
            arr[back--] = 0;
            --front;
            break;
        }
        if(back == arr.size() - 1)
        {
            break;
        }
        ++front;
    }
    while(front >= 0)
    {
        if(arr[front] == 0)
        {
            arr[back--] = 0;
            arr[back--] = 0;
            --front;
        }
        else
        {
            arr[back--] = arr[front--];
        }
    }
}
  1. 快乐数
cpp 复制代码
// 方法一
bool isHappy(int n)
{
    unordered_set<int> res({n});
    int num = 0;
    while(true)
    {
        while(n != 0)
        {
            num += pow((n % 10), 2);
            n /= 10;
        }
        if(num == 1)
        {
            return true;
        }
        else if(res.find(num) != res.end())
        {
            return false;
        }
        else
        {
            res.insert(num);
        }
        n = num;
        num = 0;
    }
}
// 方法二
int Run(int num)
{
    int ret = 0;
    while(num != 0)
    {
        ret += pow((num % 10), 2);
        num /= 10;
    }
    return ret;
}

bool isHappy(int n)
{
    int slow = n;
    int fast = n;
    while (true)
    {
        slow = Run(slow);
        fast = Run(fast);
        fast = Run(fast);
        if (slow == fast && fast == 1)
        {
            return true;
        }
        else if (slow == fast)
        {
            return false;
        }
    }
}
  1. 盛最多水的容器
cpp 复制代码
int maxArea(vector<int>& height)
{
    size_t left= 0;
    size_t right = height.size() - 1;
    size_t ret = (right - left) * min(height[left], height[right]);

    size_t tmp = 0;
    size_t area = 0;
    do
    {
        if(height[left] < height[right])
        {
            tmp = height[left];
            while(left < right && height[++left] <= tmp);
        }
        else
        {
            tmp = height[right];
            while(left < right && height[--right] <= tmp);
        }

        if(left < right)
        {
            area = (right - left) * min(height[left], height[right]);
            if(area > ret) ret = area;
        }
    }while(left < right);

    return ret;
}
  1. 有效三角形的个数
    利用单调性,先固定最大的数,在最大的数的左区间内使用双指针算法。
cpp 复制代码
inline bool check(int side1, int side2, int side3)
{
    return (side1 + side2 > side3);
}
int triangleNumber(vector<int>& nums)
{
    if(nums.size() < 3) return 0;
    sort(nums.begin(), nums.end());

    size_t max_index = nums.size() - 1;
    size_t left_index = 0;
    size_t right_index = max_index - 1;
    int ret = 0;
    while(max_index > 1)
    {
        while(left_index < right_index)
        {
            if(check(nums[left_index], nums[right_index], nums[max_index]))
            {
                ret += (right_index - left_index);
                --right_index;
            }
            else
            {
                ++left_index;
            }
        }
        --max_index;
        left_index = 0;
        right_index = max_index - 1;
    }
    return ret;
}
  1. 查找总价格为目标值的两个商品
cpp 复制代码
vector<int> twoSum(vector<int>& price, int target)
{
    size_t left = 0;
    size_t right = price.size() - 1;
    vector<int> v(2);
    while(left < right)
    {
        if(price[left] + price[right] < target)
        {
            ++left;
        }
        else if(price[left] + price[right] > target)
        {
            --right;
        }
        else
        {
            v[0] = price[left];
            v[1] = price[right];
            break;
        }
    }
    return v;
}
  1. 三数之和
    注意对去重的处理(跳过重复元素)。
cpp 复制代码
vector<vector<int>> threeSum(vector<int>& nums)
{
    vector<vector<int>> vv;
    sort(nums.begin(), nums.end());

    size_t max_index = nums.size() - 1;
    size_t left_index = 0;
    size_t right_index = max_index - 1;
    while(max_index > 1)
    {
        while(left_index < right_index)
        {
            if(nums[left_index] + nums[right_index] + nums[max_index] > 0)
            {
                while(left_index < --right_index && nums[right_index] == nums[right_index + 1]);
            }
            else if(nums[left_index] + nums[right_index] + nums[max_index] < 0)
            {
                while(++left_index < right_index && nums[left_index] == nums[left_index - 1]);
            }
            else
            {
                vv.push_back({nums[left_index], nums[right_index], nums[max_index]});
                while(left_index < --right_index && nums[right_index] == nums[right_index + 1]); // or ++left_index
            }
        }
        while(--max_index > 1 && nums[max_index] == nums[max_index + 1]);
        left_index = 0;
        right_index = max_index - 1;
    }
    return vv;
}
  1. 四数之和
    结合三数之和解题。
cpp 复制代码
long long Sum(long long num1, long long num2, long long num3)
{
    return num1 + num2 + num3;
}
void threeSum(vector<vector<int>>& vv, vector<int>& nums, size_t max_index, int max, int target)
{
    size_t left_index = 0;
    size_t right_index = max_index - 1;
    while(max_index > 1)
    {
        while(left_index < right_index)
        {
            if(Sum(nums[left_index], nums[right_index], nums[max_index]) > target)
            {
                while(left_index < --right_index && nums[right_index] == nums[right_index + 1]);
            }
            else if(Sum(nums[left_index], nums[right_index], nums[max_index]) < target)
            {
                while(++left_index < right_index && nums[left_index] == nums[left_index - 1]);
            }
            else
            {
                vv.push_back({nums[left_index], nums[right_index], nums[max_index], max});
                while(left_index < --right_index && nums[right_index] == nums[right_index + 1]);
            }
        }
        while(--max_index > 1 && nums[max_index] == nums[max_index + 1]);
        left_index = 0;
        right_index = max_index - 1;
    }
}
vector<vector<int>> fourSum(vector<int>& nums, int target)
{   
    vector<vector<int>> vv;
    if(nums.size() < 4) return vv;
    sort(nums.begin(), nums.end()); // 排序

    size_t max_index = nums.size() - 1; // 固定第4个数
    while(max_index > 2)
    {
        threeSum(vv, nums, max_index - 1, nums[max_index], target - nums[max_index]);
        while(--max_index > 2 && nums[max_index] == nums[max_index + 1]);
    }
    return vv;
}
相关推荐
cynicme1 小时前
力扣3228——将 1 移动到末尾的最大操作次数
算法·leetcode
熬了夜的程序员1 小时前
【LeetCode】109. 有序链表转换二叉搜索树
数据结构·算法·leetcode·链表·职场和发展·深度优先
随意起个昵称1 小时前
【递归】二进制字符串中的第K位
c++·算法
mjhcsp2 小时前
C++ 循环结构:控制程序重复执行的核心机制
开发语言·c++·算法
立志成为大牛的小牛2 小时前
数据结构——四十一、分块查找(索引顺序查找)(王道408)
数据结构·学习·程序人生·考研·算法
xier_ran2 小时前
深度学习:RMSprop 优化算法详解
人工智能·深度学习·算法
地平线开发者2 小时前
不同传感器前中后融合方案简介
算法·自动驾驶
Mr_WangAndy2 小时前
C++_chapter15_C++重要知识点_lambda,initializer_list
c++·lambda·初始化列表
地平线开发者2 小时前
征程 6X 常见 kernel panic 问题
算法·自动驾驶
Maple_land2 小时前
第1篇:Linux工具复盘上篇:yum与vim
linux·运维·服务器·c++·centos