C++算法题 - 数组/字符串(1)

88. 合并两个有序数组

LeetCode_link


给你两个按 非递减顺序 排列的整数数组 nums1nums2,另有两个整数 mn ,分别表示 nums1nums2 中的元素数目。

请你 合并 nums2nums1 中,使合并后的数组同样按 非递减顺序 排列。

注意:最终,合并后数组不应由函数返回,而是存储在数组 nums1 中。为了应对这种情况,nums1 的初始长度为 m + n,其中前 m 个元素表示应合并的元素,后 n 个元素为 0 ,应忽略。nums2 的长度为 n

示例 1
输入:nums1 = [1,2,3,0,0,0], m = 3, nums2 = [2,5,6], n = 3
输出:[1,2,2,3,5,6]
解释:需要合并 [1,2,3] 和 [2,5,6] 。
合并结果是 [1,2,2,3,5,6] ,其中斜体加粗标注的为 nums1 中的元素。

示例 2
输入:nums1 = [1], m = 1, nums2 = [], n = 0
输出:[1]
解释:需要合并 [1] 和 [] 。
合并结果是 [1] 。

示例 3
输入:nums1 = [0], m = 0, nums2 = [1], n = 1
输出:[1]
解释:需要合并的数组是 [] 和 [1] 。
合并结果是 [1] 。
注意,因为 m = 0 ,所以 nums1 中没有元素。nums1 中仅存的 0 仅仅是为了确保合并结果可以顺利存放到 nums1 中。

提示
nums1.length == m + n
nums2.length == n
0 <= m, n <= 200
1 <= m + n <= 200
-109 <= nums1[i], nums2[j] <= 109


class Solution {
public:
    void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {
        int num_tmp[m+n];
        int i = 0, j = 0, k = 0;
        while(i < m && j < n){
            if(nums1[i] <= nums2[j]){
                num_tmp[k++] = nums1[i++];
            }else{
                num_tmp[k++] = nums2[j++];
            }
        }
        while(i < m){
            num_tmp[k++] = nums1[i++];
        }
        while(j < n){
            num_tmp[k++] = nums2[j++];
        }
        for(int t = 0; t < m + n; t++){
            nums1[t] = num_tmp[t];
        }
    }
};

27. 移除元素

LeetCode_link


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

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

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

说明:
为什么返回数值是整数,但输出的答案是数组呢?
请注意,输入数组是以**「引用」**方式传递的,这意味着在函数里修改输入数组对于调用者是可见的。
你可以想象内部操作如下:

// nums 是以“引用”方式传递的。也就是说,不对实参作任何拷贝
int len = removeElement(nums, val);

// 在函数里修改输入数组对于调用者是可见的。
// 根据你的函数返回的长度, 它会打印出数组中 该长度范围内 的所有元素。
for (int i = 0; i < len; i++) {
print(nums[i]);
}

示例 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],也会被视作正确答案。

示例 2
输入:nums = [0,1,2,2,3,0,4,2], val = 2
输出:5, nums = [0,1,3,0,4]
解释:函数应该返回新的长度 5, 并且 nums 中的前五个元素为 0, 1, 3, 0, 4。注意这五个元素可为任意顺序。你不需要考虑数组中超出新长度后面的元素。

提示
0 <= nums.length <= 100
0 <= nums[i] <= 50
0 <= val <= 100


class Solution {
public:
    int removeElement(vector<int>& nums, int val) {
        int count = 0;
        int i = 0;
        for(i; i < nums.size(); i++){
            if(nums[i] == val){
                count ++;
            }else{
                nums[i - count] = nums[i];
            }
        }
        return  nums.size() - count; // 注意这里的边界

    }
};

26. 删除有序数组中的重复项

LeetCode_link


给你一个 非严格递增排列 的数组 nums ,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。然后返回 nums 中唯一元素的个数。

考虑 nums 的唯一元素的数量为 k ,你需要做以下事情确保你的题解可以被通过:

  • 更改数组 nums ,使 nums 的前 k 个元素包含唯一元素,并按照它们最初在 nums 中出现的顺序排列。nums 的其余元素与 nums 的大小不重要。
  • 返回 k

判题标准:
系统会用下面的代码来测试你的题解:

int[] nums = [...]; // 输入数组
int[] expectedNums = [...]; // 长度正确的期望答案

int k = removeDuplicates(nums); // 调用

assert k == expectedNums.length;
for (int i = 0; i < k; i++) {
    assert nums[i] == expectedNums[i];
}

如果所有断言都通过,那么您的题解将被 通过

示例 1
输入:nums = [1,1,2]
输出:2, nums = [1,2,_]
解释:函数应该返回新的长度 2 ,并且原数组 nums 的前两个元素被修改为 1, 2 。不需要考虑数组中超出新长度后面的元素。

示例 2
输入:nums = [0,0,1,1,1,2,2,3,3,4]
输出:5, nums = [0,1,2,3,4]
解释:函数应该返回新的长度 5 , 并且原数组 nums 的前五个元素被修改为 0, 1, 2, 3, 4 。不需要考虑数组中超出新长度后面的元素。

提示
1 <= nums.length <= 3 * 104
-104 <= nums[i] <= 104
nums 已按 非严格递增 排列


class Solution {
public:
    int removeDuplicates(vector<int>& nums) {
        int count = 0;
        int i = 1;
        int now_num = nums[0];
        for(i; i < nums.size(); i++){
            if(nums[i] == now_num){
                count++;
            }else{
                now_num = nums[i];
                nums[i - count] = nums[i];
            }
        }
        return nums.size() - count;
    }
};

80. 删除有序数组中的重复项Ⅱ

LeetCode_link
leetcode:80


给你一个有序数组 nums ,请你 原地 删除重复出现的元素,使得出现次数超过两次的元素只出现两次 ,返回删除后数组的新长度。

不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。

说明
为什么返回数值是整数,但输出的答案是数组呢?

请注意,输入数组是以「引用」方式传递的,这意味着在函数里修改输入数组对于调用者是可见的。

你可以想象内部操作如下:

// nums 是以“引用”方式传递的。也就是说,不对实参做任何拷贝
int len = removeDuplicates(nums);

// 在函数里修改输入数组对于调用者是可见的。
// 根据你的函数返回的长度, 它会打印出数组中 该长度范围内 的所有元素。
for (int i = 0; i < len; i++) {
    print(nums[i]);
}

示例 1
输入:nums = [1,1,1,2,2,3]
输出:5, nums = [1,1,2,2,3]
解释:函数应返回新长度 length = 5, 并且原数组的前五个元素被修改为 1, 1, 2, 2, 3。 不需要考虑数组中超出新长度后面的元素。

示例 2
输入:nums = [0,0,1,1,1,1,2,3,3]
输出:7, nums = [0,0,1,1,2,3,3]
解释:函数应返回新长度 length = 7, 并且原数组的前七个元素被修改为 0, 0, 1, 1, 2, 3, 3。不需要考虑数组中超出新长度后面的元素。

提示
1 <= nums.length <= 3 * 104
-104 <= nums[i] <= 104
nums 已按升序排列


class Solution {
public:
    int removeDuplicates(vector<int>& nums) {
        int count = 0;
        int count2 = 1;
        int now_num = nums[0];
        for(int i = 1; i < nums.size(); i ++){
            if(nums[i] == now_num){
                count2++;
                if(count2 > 2){
                    count++;
                    count2++;
                }else{
                    nums[i - count] = nums[i]; // 要非常注意这里,很容易遗忘!!!
                }
            }else{
                count2 = 1;
                now_num = nums[i];
                nums[i - count] = nums[i];
            }
        }
        return nums.size() - count;
    }
};

169. 多数元素

LeetCode_link


给定一个大小为 n 的数组 nums ,返回其中的多数元素。多数元素是指在数组中出现次数 大于 ⌊ n/2 ⌋ 的元素。

你可以假设数组是非空的,并且给定的数组总是存在多数元素。

示例 1
输入:nums = [3,2,3]
输出:3

示例 2
输入:nums = [2,2,1,1,1,2,2]
输出:2

提示
n == nums.length
1 <= n <= 5 * 104
-109 <= nums[i] <= 109


打擂台的方式

class Solution {
public:
    int majorityElement(vector<int>& nums) {
        int mostnum = nums[0];
        int count = 1;
        for(int i = 0; i < nums.size(); i++){
            if(nums[i] == mostnum){
                count ++;
            }else{
                count --;
                if(count == 0){
                    count = 1;
                    mostnum = nums[i];
                }
            }
        }
        return mostnum;

    }
};

189. 轮转数组

LeetCode_link


给定一个整数数组 nums,将数组中的元素向右轮转 k 个位置,其中 k 是非负数。

示例 1:
输入: nums = [1,2,3,4,5,6,7], k = 3
输出: [5,6,7,1,2,3,4]
解释:
向右轮转 1 步: [7,1,2,3,4,5,6]
向右轮转 2 步: [6,7,1,2,3,4,5]
向右轮转 3 步: [5,6,7,1,2,3,4]

示例 2:
输入:nums = [-1,-100,3,99], k = 2
输出:[3,99,-1,-100]
解释:
向右轮转 1 步: [99,-1,-100,3]
向右轮转 2 步: [3,99,-1,-100]

提示
1 <= nums.length <= 105
-231 <= nums[i] <= 231 - 1
0 <= k <= 105


转置数组的方式

class Solution {
public:
    void rotate(vector<int>& nums, int k) {
        k %= nums.size(); //注意这里防止k超出num的元素个数范围,需要取余
        exchage(nums, 0, nums.size() - 1);
        exchage(nums, 0, k - 1);
        exchage(nums, k, nums.size() - 1);

    }
    void exchage(vector<int>& nums, int left, int right){
        int i = left,j = right;
        while(i < j){
            swap(nums[i++], nums[j--]);
        }
        
    }
};

121. 买卖股票的最佳时机

LeetCode_link


给定一个数组 prices,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。

你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。

返回你可以从这笔交易中获取的最大利润。如果你不能获取任何利润,返回 0

示例 1
输入:[7,1,5,3,6,4]
输出:5
解释:在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。
注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格;同时,你不能在买入前卖出股票。

示例 2
输入:prices = [7,6,4,3,1]
输出:0
解释:在这种情况下, 没有交易完成, 所以最大利润为 0。

提示
1 <= prices.length <= 105
0 <= prices[i] <= 104


思路:让最小point和最大point之间的选择,按照递增来,一旦发现比最小point小的,就重新选择递增,但是要保存上次的最大。

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int minpoint = 0;
        int maxpoint = 0;
        int rec = 0;
        for(int i = 1; i < prices.size(); i++){
            if(prices[i] > prices[maxpoint]){
                maxpoint = i;
                int tmp = prices[maxpoint] - prices[minpoint];
                rec = max(tmp, rec);
            }
            if(prices[i] < prices[minpoint]){
                minpoint = i;
                maxpoint = i;
            }
        }
        return rec;
    }
};

122. 买卖股票的最佳时机Ⅱ

LeetCode_link


给你一个整数数组 prices ,其中 prices[i] 表示某支股票第 i 天的价格。

在每一天,你可以决定是否购买和/或出售股票。你在任何时候 最多 只能持有 一股 股票。你也可以先购买,然后在 同一天 出售。

返回 你能获得的 最大 利润 。

示例 1
输入:prices = [7,1,5,3,6,4]
输出:7
解释:在第 2 天(股票价格 = 1)的时候买入,在第 3 天(股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5 - 1 = 4 。
随后,在第 4 天(股票价格 = 3)的时候买入,在第 5 天(股票价格 = 6)的时候卖出, 这笔交易所能获得利润 = 6 - 3 = 3 。
总利润为 4 + 3 = 7 。

示例 2
输入:prices = [1,2,3,4,5]
输出:4
解释:在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5 - 1 = 4 。
总利润为 4 。

示例 3
输入:prices = [7,6,4,3,1]
输出:0
解释:在这种情况下, 交易无法获得正利润,所以不参与交易可以获得最大利润,最大利润为 0 。

提示
1 <= prices.length <= 3 * 104
0 <= prices[i] <= 104


思路:找最大值时,一旦找到降低的趋势,就要抛售,然后第二天再买入。

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int minp = 0;
        int maxp = 0;
        int rec = 0;
        int maxprice = 0;
        for(int i = 1; i < prices.size(); i ++){
            if(prices[i] > prices[maxp]){
                maxp = i;
                maxprice = prices[maxp] - prices[minp];
            }
            if(prices[i] < prices[maxp]){ // 降低趋势就抛售
                rec += maxprice;
                maxprice = 0;
                minp = i;
                maxp = i;
            }
        }
        rec += maxprice;
        return rec;
    }
};

55. 跳跃游戏

LeetCode_link


给你一个非负整数数组 nums ,你最初位于数组的 第一个下标 。数组中的每个元素代表你在该位置可以跳跃的最大长度。

判断你是否能够到达最后一个下标,如果可以,返回 true ;否则,返回 false

示例 1
输入:nums = [2,3,1,1,4]
输出:true
解释:可以先跳 1 步,从下标 0 到达下标 1, 然后再从下标 1 跳 3 步到达最后一个下标。

示例 2
输入:nums = [3,2,1,0,4]
输出:false
解释:无论怎样,总会到达下标为 3 的位置。但该下标的最大跳跃长度是 0 , 所以永远不可能到达最后一个下标。

提示
1 <= nums.length <= 104
0 <= nums[i] <= 105


需要考虑的问题
1、注意是可以跳跃的最大长度,即跳跃时不一定需要跳这个距离,例[2, 5, 0, 0]也是可以跳跃到最终位置的,第一次的2时只跳跃1,这样第二次最多可以跳跃5,就可以跳跃到最终的位置
2、[*]只有一个数据的时候,无论其是否是0,都已经在最终的位置上

思路:遍历数组的同时更新能够跳跃的最远的地方的下标,同时,一旦能够条约的最远的下表超过了数组的长度,则停止遍历。

class Solution {
public:
    bool canJump(vector<int>& nums) {
        if(nums.size() == 1)    return true;
        int maxjump = nums[0];
        for(int i = 0; i < nums.size() - 1 && i <= maxjump; i++){ //这里的i <= maxjump的等于号不能丢,不然[1,2,3]就无法通过
            maxjump = max(maxjump, nums[i] + i);
            if(maxjump >= nums.size() - 1){
                return true;
            }
        }
        return false;
    }
};

45. 跳跃问题Ⅱ

LeetCode_link


给定一个长度为 n0 索引整数数组 nums。初始位置为 nums[0]

每个元素 nums[i] 表示从索引 i 向前跳转的最大长度。换句话说,如果你在 nums[i] 处,你可以跳转到任意 nums[i + j] 处:

  • 0 <= j <= nums[i]
  • i + j < n
    返回到达 nums[n - 1] 的最小跳跃次数。生成的测试用例可以到达 nums[n - 1]

示例 1:
输入: nums = [2,3,1,1,4]
输出: 2
解释: 跳到最后一个位置的最小跳跃数是 2。
从下标为 0 跳到下标为 1 的位置,跳 1 步,然后跳 3 步到达数组的最后一个位置。

示例 2:
输入: nums = [2,3,0,1,4]
输出: 2

提示:
1 <= nums.length <= 104
0 <= nums[i] <= 1000
题目保证可以到达 nums[n-1]


思路:动态规划的想法,需要额外的存储空间
注意:要注意二重循环中j的边界问题

class Solution {
public:
    int jump(vector<int>& nums) {
        vector<int> count(nums.size(), 0);
        for(int i = nums.size() - 2; i >= 0; i --){
            int mincount = nums.size() + 2;
            for(int j = i + 1; j <= i + nums[i] && j < nums.size(); j ++){
                mincount = min(mincount, count[j] + 1);
            }
            count[i] = mincount;
        }
        return count[0];

    }
};

思路:扩展边界,end 维护的是当前这一跳能达到的最右位置,若要超过该位置必须要进行一次跳跃,因此需将跳跃次数加1,并更新这次跳跃能到达的最右位置。

class Solution {
public:
    int jump(vector<int>& nums) {
        int maxpoint = 0, step = 0;
        int end = 0;
        int n = nums.size();
        for(int i = 0; i < n - 1; i ++){
             if(maxpoint >= i){ //这个判断是保证能够到达,可去除
                 maxpoint = max(maxpoint, nums[i] + i);
                 if(i == end){
                     end = maxpoint;
                     step++;
                 }
             }

        }
        return step;
    }
};

274. H指数

LeetCode_link


给你一个整数数组 citations ,其中 citations[i] 表示研究者的第 i 篇论文被引用的次数。计算并返回该研究者的 h 指数

根据维基百科上 h 指数的定义:h 代表“高引用次数” ,一名科研人员的 h 指数 是指他(她)至少发表了 h 篇论文,并且 至少 有 h 篇论文被引用次数大于等于 h 。如果 h 有多种可能的值,h 指数 是其中最大的那个。

示例 1
输入:citations = [3,0,6,1,5]
输出:3
解释:给定数组表示研究者总共有 5 篇论文,每篇论文相应的被引用了 3, 0, 6, 1, 5 次。
由于研究者有 3 篇论文每篇 至少 被引用了 3 次,其余两篇论文每篇被引用 不多于 3 次,所以她的 h 指数3

示例 2
输入:citations = [1,3,1]
输出:1

提示
n == citations.length
1 <= n <= 5000
0 <= citations[i] <= 1000


方法:排序
时间复杂度 O ( n   l o g   n ) O(n\ log\ n) O(n log n)。空间复杂度 O ( l o g   n ) O(log\ n) O(log n)

class Solution {
public:
    int hIndex(vector<int>& citations) {
        sort(citations.rbegin(), citations.rend());  // 降序排列
        for(int i = citations.size() - 1; i >=0; i --){
            if(citations[i] >= i + 1){
                return i + 1;
            }
        }
        return 0;
    }
};

方法:计数排序
时间复杂度 O ( n ) O(n) O(n)。空间复杂度 O ( n ) O(n) O(n)

class Solution {
public:
    int hIndex(vector<int>& citations) {
        int n = citations.size();
        vector<int> count(n + 1);
        for(int i = 0; i < n; i++){
            if(citations[i] < n){
                count[citations[i]] ++; 
            }else{
                count[n] ++;
            }
        }
        int sum = 0;
        for(int i = n; i >= 0; i--){
            sum += count[i];
            if(sum >= i)    return i;
        }
        return 0;
    }
};

380. O(1) 时间插入、删除和获取随机元素

LeetCode_link


实现RandomizedSet类:

  • RandomizedSet() 初始化 RandomizedSet 对象
  • bool insert(int val) 当元素 val 不存在时,向集合中插入该项,并返回 true ;否则,返回 false
  • bool remove(int val) 当元素 val 存在时,从集合中移除该项,并返回 true ;否则,返回 false
  • int getRandom() 随机返回现有集合中的一项(测试用例保证调用此方法时集合中至少存在一个元素)。每个元素应该有 相同的概率 被返回。
    你必须实现类的所有函数,并满足每个函数的 平均 时间复杂度为 O ( 1 ) O(1) O(1)

示例

输入
["RandomizedSet", "insert", "remove", "insert", "getRandom", "remove", "insert", "getRandom"]
[[], [1], [2], [2], [], [1], [2], []]
输出
[null, true, false, true, 2, true, false, 2]

解释
RandomizedSet randomizedSet = new RandomizedSet();
randomizedSet.insert(1); // 向集合中插入 1 。返回 true 表示 1 被成功地插入。
randomizedSet.remove(2); // 返回 false ,表示集合中不存在 2 。
randomizedSet.insert(2); // 向集合中插入 2 。返回 true 。集合现在包含 [1,2] 。
randomizedSet.getRandom(); // getRandom 应随机返回 1 或 2 。
randomizedSet.remove(1); // 从集合中移除 1 ,返回 true 。集合现在包含 [2] 。
randomizedSet.insert(2); // 2 已在集合中,所以返回 false 。
randomizedSet.getRandom(); // 由于 2 是集合中唯一的数字,getRandom 总是返回 2 。

提示
-231 <= val <= 231 - 1
最多调用 insertremovegetRandom 函数 2 * 105 次
在调用 getRandom 方法时,数据结构中 至少存在一个 元素。


方法:变长数组+哈希表

思路
变长数组可以在 O ( 1 ) O(1) O(1) 的时间内完成获取随机元素操作,但是由于无法在 O ( 1 ) O(1) O(1) 的时间内判断元素是否存在,因此不能在 O ( 1 ) O(1) O(1) 的时间内完成插入和删除操作。
哈希表可以在 O ( 1 ) O(1) O(1) 的时间内完成插入和删除操作,但是由于无法根据下标定位到特定元素,因此不能在 O ( 1 ) O(1) O(1) 的时间内完成获取随机元素操作。
为了满足插入、删除和获取随机元素操作的时间复杂度都是 O ( 1 ) O(1) O(1) ,需要将变长数组和哈希表结合,变长数组中存储元素,哈希表中存储每个元素在变长数组中的下标。

——力扣官方题解

在这里插入图片描述

class RandomizedSet {
private:
    unordered_map<int,int> hash;
    vector<int> v;  //动态数组
public:
    RandomizedSet() {

    }
    
    bool insert(int val) {
        if(hash.find(val) != hash.end())    return false;
        v.push_back(val);
        hash[val] = v.size() - 1;
        return true;
    }
    
    bool remove(int val) {
        if(hash.find(val) == hash.end())    return false;
        int last = v.size() - 1;
        int point = hash[val];
        //修改动态数组
        v[point] = v[last];
        v.pop_back();
        //修改哈希表
        hash[v[last]] = point;
        hash.erase(val);  // 哈希表中删除val项,必须擦除,不然当插入之前被删除的数据时,会插入失败
        return true;
    }
    
    int getRandom() {
        int size = v.size();
        int point_rand = rand() % size;
        return v[point_rand];
    }
};

/**
 * Your RandomizedSet object will be instantiated and called as such:
 * RandomizedSet* obj = new RandomizedSet();
 * bool param_1 = obj->insert(val);
 * bool param_2 = obj->remove(val);
 * int param_3 = obj->getRandom();
 */

unordered_map 是 C++ 标准库中的一种关联容器,它提供了键值对的存储能力。与 map 相比,unordered_map 的主要区别在于它内部使用哈希表来存储元素,而不是红黑树。这导致了几个关键的性能和行为差异:

  • 哈希函数:unordered_map 通过使用哈希函数来计算每个键的哈希值,并使用这个哈希值来将键值对存储在内部的哈希表中。这种机制使得 unordered_map 在平均情况下可以提供更快的查找、插入和删除操作的时间复杂度(通常为 O(1)),但最坏情况下仍可能退化到 O(n)。
  • 顺序:由于 unordered_map 基于哈希表,它不会按照键的顺序来存储元素。相反,元素的存储位置完全依赖于它们键的哈希值。这意味着遍历 unordered_map 时,元素的出现顺序是不确定的,与它们被插入的顺序或键的排序顺序无关。
  • 键的唯一性:与 map 相同,unordered_map 中的键也必须是唯一的。每个键只能关联一个值。
  • 性能考量:由于 unordered_map 使用哈希表,它在处理大量元素时通常比基于红黑树的 map 更高效。然而,这也取决于哈希函数的质量和冲突处理机制。

unordered_map 通常在那些不需要元素排序但需要快速查找能力的场合中使用。例如,当你需要经常插入和查找键值对,而且不关心它们的顺序时,unordered_map 是一个很好的选择

  • 22
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
凯撒密码是一种简单的加密算法,它将明文中的每一个字母都按照一个固定的偏移量进行移位,从而生成密文。在 C/C++ 中,可以使用数组字符串来实现凯撒密码。 以下是一个简单的凯撒密码加密程序的示例代码: ```c++ #include <stdio.h> #include <string.h> void encrypt(char *str, int offset) { int len = strlen(str); for (int i = 0; i < len; i++) { if (str[i] >= 'a' && str[i] <= 'z') { str[i] = (str[i] - 'a' + offset) % 26 + 'a'; } else if (str[i] >= 'A' && str[i] <= 'Z') { str[i] = (str[i] - 'A' + offset) % 26 + 'A'; } } } int main() { char str[100]; int offset; printf("请输入明文:"); scanf("%s", str); printf("请输入偏移量:"); scanf("%d", &offset); encrypt(str, offset); printf("密文为:%s\n", str); return 0; } ``` 在上面的代码中,我们定义了一个 `encrypt` 函数来进行加密操作。该函数接受两个参数,第一个参数是要加密的字符串,第二个参数是偏移量。在函数中,我们使用了一个循环来遍历字符串中的每一个字符。如果该字符是小写字母,则将其转换成数字 0~25,加上偏移量后再取模,最后再转换成对应的小写字母;如果该字符是大写字母,则同样进行相应的操作。 在 `main` 函数中,我们首先从用户输入中读取明文和偏移量,然后调用 `encrypt` 函数进行加密操作,最后输出加密后的密文。 注意,在实际应用中,凯撒密码很容易被破解,因为它的加密方式非常简单。因此,如果需要更加安全的加密方式,应该使用更加复杂的加密算法
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

x_fengmo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值