C++数据结构和算法代码模板总结——算法部分

数据结构和算法学*了将*两周,及时总结和整理一下相关的知识点温故而知新。

(一)C++双指针,有个经典的问题:荷兰国旗问题。【leetcode】75.颜色分类

复制代码
public void sortColor(vector<int>& nums){
    int low = 0, moid = 0, high = nums.size() -1 ;
    while(mid <= high) {
        if(nums[mid] == 0) {
            swap(nums[low],nums[mid]);
            low++;
            mid++;
        } else if(nums[mid] ==1 ){
            mid++;
        } else {
            swap(nums[mid],mid[high]);
            high--;
        }
    }
}

滑动窗⼝ :滑动窗⼝的核⼼思想是维护⼀个窗⼝ [left, righ

t] ,使得窗⼝内的字符不重复,并不断尝试扩⼤窗⼝以找到最⻓的⽆重复字符⼦串

⽆重复字符的最⻓⼦串

复制代码
class Solution {
public:
    int lengthOfLongestSubstring(string s) {
    int left = 0, maxLen = 0;
    unordered_map<char, int> charIndex;
    for (int right = 0; right < s.size(); ++right) {
        if (charIndex.find(s[right]) != charIndex.end()) {
            left = max(left, charIndex[s[right]] + 1);
    }
        charIndex[s[right]] = right;
        maxLen = max(maxLen, right - left + 1);
    }
        return maxLen;
 }
};

递归

例子:归并排序(递归的思路):

1.分解:将数组分成两部分,直到每个⼦数组只有⼀个元素。

2.解决:递归地对每个⼦数组进⾏排序。

3.合并:将排序后的⼦数组合并成⼀个有序数组。

复制代码
#include < iostream > 
#include < vector >
using namespace std;
void merge(vector < int > & nums, int left, int mid, int right) {
    vector < int > temp(right - left + 1);
    int i = left, j = mid + 1, k = 0;
    while (i <= mid && j <= right) {
        if (nums[i] <= nums[j]) {
            temp[k++] = nums[i++];
        } else {
            temp[k++] = nums[j++];
        }
    }
    while (i <= mid) {
        temp[k++] = nums[i++];
    }
    while (j <= right) {
        temp[k++] = nums[j++];
    }
    for (i = left, k = 0; i <= right; ++i, ++k) {
        nums[i] = temp[k];
    }
}
void mergeSort(vector < int > & nums, int left, int right) {
    if (left >= right) return;
    int mid = left + (right - left) / 2;
    mergeSort(nums, left, mid);
    mergeSort(nums, mid + 1, right);
    merge(nums, left, mid, right);
}

二分法:

复制代码
int binarySearch(vector < int > & nums, int target) {
    int left = 0, right = nums.size() - 1;
    while (left <= right) {
        int mid = left + (right - left) / 2;
        if (nums[mid] == target) return mid;
        else if (nums[mid] < target) left = mid + 1;
        else right = mid - 1;
    }
    return -1;
}

动态规划:动态规划最麻烦的点是写出状态转移方程。

零钱兑换问题 :322. 零钱兑换

状态转移⽅程:dp[i] = min(dp[i], dp[i - coin] + 1

写出动态转移方程的通用流程:

1、确定「状态」,也就是原问题和子问题中会变化的变量。由于硬币数量无限,硬币的面额也是题目给定的,只有目标金额会不断地向 base case 靠*,所以唯一的「状态」就是目标金额 amount。

2、确定「选择」,也就是导致「状态」产生变化的行为。目标金额为什么变化呢,因为你在选择硬币,你每选择一枚硬币,就相当于减少了目标金额。所以说所有硬币的面值,就是你的「选择」。

3、明确 dp 函数/数组的定义。我们这里讲的是自顶向下的解法,所以会有一个递归的 dp 函数,一般来说函数的参数就是状态转移中会变化的量,也就是上面说到的「状态」;函数的返回值就是题目要求我们计算的量。就本题来说,状态只有一个,即「目标金额」,题目要求我们计算凑出目标金额所需的最少硬币数量。

所以我们可以这样定义 dp 函数:dp(n) 表示,输入一个目标金额 n,返回凑出目标金额 n 所需的最少硬币数量。

那么根据这个定义,我们的最终答案就是 dp(amount) 的返回值。

代码实现:

复制代码
class Solution {
public:
    int coinChange(vector<int>& coins, int amount) {
        int max = amount + 1;
        vector<int> dp(amount + 1, max); // 初始化dp数组,所有值设为amount+1
        dp[0] = 0; // dp[0]初始化为0,表示金额为0时需要的硬币数量为0

        // 遍历每个金额,从1到amount
        for (int i = 1; i <= amount; i++) {
            // 遍历每种硬币
            for (int j = 0; j < coins.size(); j++) {
                // 如果当前硬币面额小于等于当前金额
                if (coins[j] <= i) {
                    // 更新dp[i],取当前值和dp[i - coins[j]] + 1的最小值
                    dp[i] = min(dp[i], dp[i - coins[j]] + 1);
                }
            }
        }

        // 如果dp[amount]大于amount,说明无法凑成总金额,返回-1
        return dp[amount] > amount ? -1 : dp[amount];
    }
};
相关推荐
mochensage43 分钟前
CSP信奥赛C++常用系统函数汇总
c++·信奥
mochensage44 分钟前
C++信息学竞赛中常用函数的一般用法
java·c++·算法
fpcc1 小时前
跟我学c++中级篇——多线程中的文件处理
c++
5:002 小时前
云备份项目
linux·开发语言·c++
乄夜2 小时前
嵌入式面试高频(5)!!!C++语言(嵌入式八股文,嵌入式面经)
c语言·c++·单片机·嵌入式硬件·物联网·面试·职场和发展
YYDS3143 小时前
C++动态规划-01背包
开发语言·c++·动态规划
wydaicls3 小时前
十一.C++ 类 -- 面向对象思想
开发语言·c++
姜君竹4 小时前
QT的工程文件.pro文件
开发语言·c++·qt·系统架构
小猫咪怎么会有坏心思呢4 小时前
华为OD机考 - 水仙花数 Ⅰ(2025B卷 100分)
数据结构·链表·华为od