LeetCode面试经典150题C++实现,更新中

用C++实现下面网址的题目

https://leetcode.cn/problems/merge-sorted-array/?envType=study-plan-v2&envId=top-interview-150

1、数组\字符串

88合并两个有序数组

以下是使用 C++ 实现合并两个有序数组的代码及测试用例

C++代码实现

#include <iostream>
#include <vector>

using namespace std;

class Solution {
public:
    // 合并两个有序数组的函数
    void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {
        // 初始化三个指针,i指向nums1有效元素的末尾,j指向nums2的末尾,k指向合并后nums1的末尾
        int i = m - 1; 
        int j = n - 1;
        int k = m + n - 1;

        // 当nums1和nums2都还有未处理的元素时
        while (i >= 0 && j >= 0) {
            if (nums1[i] > nums2[j]) {
                // 如果nums1中当前元素大于nums2中当前元素,将nums1中的元素移到合并后的位置
                nums1[k] = nums1[i];
                i--;
            } else {
                // 如果nums2中当前元素大于等于nums1中当前元素,将nums2中的元素移到合并后的位置
                nums1[k] = nums2[j];
                j--;
            }
            k--;
        }

        // 如果nums2还有剩余元素,将它们全部复制到nums1的前面部分
        while (j >= 0) {
            nums1[k] = nums2[j];
            j--;
            k--;
        }
    }
};

// 测试用例函数
void testMerge() {
    Solution solution;
    // 测试示例1
    vector<int> nums1_1 = {1, 2, 3, 0, 0, 0};
    int m1 = 3;
    vector<int> nums2_1 = {2, 5, 6};
    int n1 = 3;
    solution.merge(nums1_1, m1, nums2_1, n1);
    for (int num : nums1_1) {
        cout << num << " ";
    }
    cout << endl;

    // 测试示例2
    vector<int> nums1_2 = {4, 5, 6, 0, 0, 0};
    int m2 = 3;
    vector<int> nums2_2 = {1, 2, 3};
    int n2 = 3;
    solution.merge(nums1_2, m2, nums2_2, n2);
    for (int num : nums1_2) {
        cout << num << " ";
    }
    cout << endl;

    // 测试示例3(nums1为空数组,用0填充)
    vector<int> nums1_3 = {0, 0, 0};
    int m3 = 0;
    vector<int> nums2_3 = {1, 2, 3};
    int n3 = 3;
    solution.merge(nums1_3, m3, nums2_3, n3);
    for (int num : nums1_3) {
        cout << num << " ";
    }
    cout << endl;
}

int main() {
    testMerge();
    return 0;
}

以下是对代码的详细注释:

merge函数注释

  1. 函数参数和初始化指针

    • vector<int>& nums1:这是第一个有序数组,它有足够的空间来容纳合并后的结果。我们通过引用传递它,以避免复制大型数组。
    • int m:表示nums1中实际有效元素的个数。
    • vector<int>& nums2:第二个有序数组。
    • int n:表示nums2中元素的个数。
    • 初始化ijk三个指针:
      • int i = m - 1i指向nums1中有效元素部分的末尾,用于从后往前遍历nums1的有效元素。
      • int j = n - 1j指向nums2的末尾,用于从后往前遍历nums2
      • int k = m + n - 1k指向nums1用于填充合并结果的末尾位置,因为合并后的数组长度是m + n
  2. 合并过程的主循环

    • while (i >= 0 && j >= 0):只要nums1nums2都还有未处理的元素,就继续循环。
    • 在循环内:
      • if (nums1[i] > nums2[j]):比较nums1nums2当前指向的元素大小。如果nums1[i]更大,就将nums1[i]移到nums1的合并后位置nums1[k],然后i减 1(因为这个元素已经处理了),k也减 1(移动到下一个合并后的位置)。
      • 否则(nums2[j] >= nums1[i]),将nums2[j]移到nums1[k],然后j减 1,k减 1。
  3. 处理nums2剩余元素

    • while (j >= 0):当nums2还有剩余元素(nums1已经处理完或者处理过程中nums2还有剩余)时,将nums2的剩余元素依次复制到nums1的前面部分(因为nums1有足够的空间),每次复制后j减 1,k减 1。

testMerge函数注释

  1. 创建Solution对象和测试示例数据

    • Solution solution:创建Solution类的一个实例,用于调用merge函数。
    • 对于每个测试示例:
      • 定义nums1mnums2n。例如在第一个测试示例中:
        • vector<int> nums1_1 = {1, 2, 3, 0, 0, 0}nums1_1是第一个有序数组,后面的0是用于填充合并结果的额外空间。
        • int m1 = 3:表示nums1_1中实际有效元素的个数是 3 个。
        • vector<int> nums2_1 = {2, 5, 6}:第二个有序数组。
        • int n1 = 3nums2_1中元素的个数是 3 个。
  2. 调用merge函数并输出结果

    • 调用solution.merge(nums1_1, m1, nums2_1, n1)来合并两个数组。
    • 然后使用for循环for (int num : nums1_1)遍历合并后的nums1_1数组,并输出每个元素,用于查看合并结果是否正确。每个测试示例都重复这个过程。

main函数注释

main函数中,只调用了testMerge函数来执行所有的测试用例,最后返回 0,表示程序正常结束。

代码提交测试结果如下:3b082fe749714f9880ed27ff58f9caef.png

27移除元素

以下是使用 C++ 实现移除数组中指定元素的代码,并包含了测试用例:

C++代码实现

#include <iostream>
#include <vector>

using namespace std;

class Solution {
public:
    // 函数用于移除向量nums中的指定元素val
    int removeElement(vector<int>& nums, int val) {
        int i = 0;  // 慢指针,用于标记新数组的索引位置

        // 遍历整个nums数组,j为快指针
        for (int j = 0; j < nums.size(); j++) {
            // 如果当前元素不等于要移除的值val
            if (nums[j]!= val) {
                nums[i] = nums[j];  // 将当前元素复制到新数组的位置(由慢指针i指定)
                i++;  // 慢指针后移一位,准备接收下一个新元素
            }
        }
        return i;  // 返回新数组的长度(即移除指定元素后的数组长度)
    }
};

// 测试用例函数
void testRemoveElement() {
    Solution solution;
    // 测试示例1
    vector<int> nums1 = {3, 2, 2, 3};
    int val1 = 3;
    int newSize1 = solution.removeElement(nums1, val1);
    for (int k = 0; k < newSize1; k++) {
        cout << nums1[k] << " ";
    }
    cout << endl;

    // 测试示例2
    vector<int> nums2 = {0, 1, 2, 2, 3, 0, 4, 2};
    int val2 = 2;
    int newSize2 = solution.removeElement(nums2, val2);
    for (int k = 0; k < newSize2; k++) {
        cout << nums2[k] << " ";
    }
    cout << endl;

    // 测试示例3(数组中没有要移除的元素)
    vector<int> nums3 = {1, 3, 5, 7};
    int val3 = 2;
    int newSize3 = solution.removeElement(nums3, val3);
    for (int k = 0; k < newSize3; k++) {
        cout << nums3[k] << " ";
    }
    cout << endl;
}

int main() {
    testRemoveElement();
    return 0;
}

以下是对代码的详细注释:

removeElement函数注释

  • 参数和慢指针初始化

    • vector<int>& nums:这是一个引用传递的整数向量,我们要在这个向量中移除指定元素。引用传递可以避免在函数调用时复制整个向量,提高效率。
    • int val:要从nums向量中移除的目标元素值。
    • int i = 0:定义一个慢指针i,它用于标记新数组的索引位置。新数组是指移除指定元素val后的数组。
  • 遍历数组和移除元素的过程

    • 使用for循环for (int j = 0; j < nums.size(); j++)来遍历整个nums向量,这里j是快指针。
    • 在循环内部,通过if (nums[j]!= val)判断当前元素nums[j]是否不等于要移除的值val
    • 如果nums[j]不等于val,就执行nums[i] = nums[j];,这意味着将当前元素(不需要移除的元素)复制到新数组的位置(由慢指针i指定)。
    • 然后执行i++;,将慢指针i向后移动一位,准备接收下一个不需要移除的元素。
  • 返回新数组长度

    • 当遍历完整个nums向量后,i的值就是新数组的长度,也就是移除指定元素val后的数组长度,最后将i返回。

testRemoveElement函数注释

  • 创建Solution对象和测试数据

    • Solution solution:创建Solution类的一个实例,用于调用removeElement函数。
    • 对于每个测试示例:
      • 定义nums向量和val值。例如在第一个测试示例中:
        • vector<int> nums1 = {3, 2, 2, 3}:定义了一个整数向量nums1,其中包含要操作的数组元素。
        • int val1 = 3:指定要从nums1中移除的元素值为3
  • 调用removeElement函数并输出结果

    • 调用solution.removeElement(nums1, val1)来移除nums1中的val1元素,并将返回的新数组长度存储在newSize1中。
    • 使用for循环for (int k = 0; k < newSize1; k++)遍历新数组(即移除指定元素后的nums1部分),并输出每个元素,以便查看移除结果是否正确。每个测试示例都重复这个过程。

main函数注释

  • main函数中,只调用了testRemoveElement函数来执行所有的测试用例,最后返回0,表示程序正常结束。

代码提交测试结果如下: 

57c5a6dddee142b195d64ef039ba66bb.png

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

以下是使用 C++ 实现删除有序数组中的重复项的代码,并包含测试用例:

C++代码实现 

#include <iostream>
#include <vector>

using namespace std;

class Solution {
public:
    // 函数用于删除有序数组nums中的重复项
    int removeDuplicates(vector<int>& nums) {
        if (nums.size() == 0) {
            return 0;
        }
        int i = 0; // 慢指针,指向不重复元素的位置
        for (int j = 1; j < nums.size(); j++) { // 快指针,用于遍历数组
            if (nums[j]!= nums[i]) { 
                i++;
                nums[i] = nums[j];
            }
        }
        return i + 1; // 返回不重复元素的个数,因为索引从0开始,所以个数为i + 1
    }
};

// 测试用例函数
void testRemoveDuplicates() {
    Solution solution;
    // 测试示例1
    vector<int> nums1 = {1, 1, 2};
    int newLength1 = solution.removeDuplicates(nums1);
    for (int k = 0; k < newLength1; k++) {
        cout << nums1[k] << " ";
    }
    cout << endl;

    // 测试示例2
    vector<int> nums2 = {0, 0, 1, 1, 1, 2, 2, 3, 3, 4};
    int newLength2 = solution.removeDuplicates(nums2);
    for (int k = 0; k < newLength2; k++) {
        cout << nums2[k] << " ";
    }
    cout << endl;

    // 测试示例3(没有重复元素的数组)
    vector<int> nums3 = {5, 6, 7, 8};
    int newLength3 = solution.removeDuplicates(nums3);
    for (int k = 0; k < newLength3; k++) {
        cout << nums3[k] << " ";
    }
    cout << endl;
}

int main() {
    testRemoveDuplicates();
    return 0;
}

以下是对代码的详细注释:

removeDuplicates函数注释

  • 边界情况处理

    • 首先判断数组是否为空,如果nums.size() == 0,则直接返回0,因为空数组没有元素,也就没有重复项需要处理。
  • 初始化指针和遍历数组

    • int i = 0:定义一个慢指针i,它用于标记不重复元素的位置。初始时,数组的第一个元素必然是不重复的,所以i初始化为0
    • 使用for循环for (int j = 1; j < nums.size(); j++)来遍历数组,这里j是快指针,从索引1开始,因为我们已经将i初始化为0,即第一个元素已经考虑过了。
  • 处理重复元素

    • 在循环内部,通过if (nums[j]!= nums[i])判断当前元素nums[j]是否与慢指针i所指向的元素不同。
    • 如果不同,说明找到了一个新的不重复元素。首先将慢指针i向后移动一位(i++),然后将新的不重复元素nums[j]赋值给nums[i],这样就将不重复元素依次向前移动。
  • 返回不重复元素个数

    • 当遍历完整个数组后,由于索引从0开始,不重复元素的个数就是i + 1,所以返回i + 1

testRemoveDuplicates函数注释

  • 创建Solution对象和测试数据

    • Solution solution:创建Solution类的一个实例,用于调用removeDuplicates函数。
    • 对于每个测试示例:
      • 定义nums向量。例如在第一个测试示例中:
        • vector<int> nums1 = {1, 1, 2}:定义了一个有序整数向量nums1,其中包含重复元素。
  • 调用removeDuplicates函数并输出结果

    • 调用solution.removeDuplicates(nums1)来删除nums1中的重复元素,并将返回的不重复元素个数存储在newLength1中。
    • 使用for循环for (int k = 0; k < newLength1; k++)遍历处理后的数组(即不重复元素部分),并输出每个元素,以便查看删除重复项的结果是否正确。每个测试示例都重复这个过程。

main函数注释

  • main函数中,只调用了testRemoveDuplicates函数来执行所有的测试用例,最后返回0,表示程序正常结束。

代码提交测试结果如下:  

163ee26bb4da4fcaab6cc45669a08857.png

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

以下是使用 C++ 实现删除有序数组中的重复项 II 的代码,允许每个元素最多出现两次:

C++代码实现 

#include <iostream>
#include <vector>

using namespace std;

class Solution {
public:
    int removeDuplicates(vector<int>& nums) {
        if (nums.size() <= 2) {
            return nums.size();
        }
        int i = 2; // 慢指针,从索引2开始,因为前两个元素不管是否重复都保留
        for (int j = 2; j < nums.size(); j++) {
            // 如果当前元素与慢指针前两个位置的元素不相等,说明当前元素不是重复超过2次的元素
            if (nums[j]!= nums[i - 2]) { 
                nums[i] = nums[j];
                i++;
            }
        }
        return i;
    }
};

// 测试用例函数
void testRemoveDuplicatesII() {
    Solution solution;
    // 测试示例1
    vector<int> nums1 = {1, 1, 1, 2, 2, 3};
    int newLength1 = solution.removeDuplicates(nums1);
    for (int k = 0; k < newLength1; k++) {
        cout << nums1[k] << " ";
    }
    cout << endl;

    // 测试示例2
    vector<int> nums2 = {0, 0, 1, 1, 1, 1, 2, 3, 3};
    int newLength2 = solution.removeDuplicates(nums2);
    for (int k = 0; k < newLength2; k++) {
        cout << nums2[k] << " ";
    }
    cout << endl;

    // 测试示例3(没有重复元素的数组)
    vector<int> nums3 = {2, 3, 5, 7};
    int newLength3 = solution.removeDuplicates(nums3);
    for (int k = 0; k < newLength3; k++) {
        cout << nums3[k] << " ";
    }
    cout << endl;
}

int main() {
    testRemoveDuplicatesII();
    return 0;
}

以下是详细注释:

removeDuplicates函数注释

  • 边界情况处理

    • 首先判断数组大小,如果nums.size() <= 2,那么数组中的元素最多重复两次或者没有重复,直接返回数组的大小。
  • 初始化指针和遍历数组

    • int i = 2:慢指针i从索引2开始,因为我们允许每个元素最多出现两次,所以前两个元素不管是否重复都先保留。
    • 使用for循环for (int j = 2; j < nums.size(); j++),其中j是快指针,从索引2开始遍历整个数组。
  • 处理重复元素

    • 在循环中,通过if (nums[j]!= nums[i - 2])判断当前元素nums[j]是否与慢指针i往前数两个位置的元素不相等。如果不相等,说明当前元素不是重复超过两次的元素。
    • 当满足条件时,将nums[j]赋值给nums[i],然后将慢指针i向后移动一位(i++),这样就将不重复或者重复次数未超过两次的元素依次向前移动。
  • 返回处理后的数组长度

    • 当遍历完整个数组后,慢指针i的值就是处理后的数组长度,返回i

testRemoveDuplicatesII函数注释

  • 创建Solution对象和测试数据

    • Solution solution:创建Solution类的一个实例,用于调用removeDuplicates函数。
    • 对于每个测试示例:
      • 定义nums向量。例如在第一个测试示例中,vector<int> nums1 = {1, 1, 1, 2, 2, 3}定义了一个有序整数向量nums1,其中有重复元素。
  • 调用removeDuplicates函数并输出结果

    • 调用solution.removeDuplicates(nums1)来处理nums1中的重复元素,并将返回的新数组长度存储在newLength1中。
    • 使用for循环for (int k = 0; k < newLength1; k++)遍历处理后的数组,并输出每个元素,以此来查看处理结果是否正确。每个测试示例都重复这个过程。

main函数注释

  • main函数中,调用testRemoveDuplicatesII函数来执行所有的测试用例,最后返回0,表示程序正常结束。

代码提交测试结果如下:   

2b196e18ef084672914d2ef5b2a64df2.png

169. 多数元素

利用哈希表统计出现次数的方法

C++代码实现

#include <iostream>
#include <vector>
#include <unordered_map>

using namespace std;

class Solution {
public:
    int majorityElement(vector<int>& nums) {
        // 创建一个无序映射(哈希表)来存储元素及其出现的次数
        unordered_map<int, int> countMap;
        int n = nums.size();
        // 遍历数组,统计每个元素出现的次数
        for (int num : nums) {
            if (countMap.find(num)!= countMap.end()) {
                countMap[num]++;
            } else {
                countMap[num] = 1;
            }
            // 如果某个元素的出现次数超过数组长度的一半,返回该元素
            if (countMap[num] > n / 2) {
                return num;
            }
        }
        return -1; // 如果没有找到多数元素,返回 -1(实际情况中多数元素一定存在)
    }
};

// 测试用例函数
void testMajorityElement() {
    Solution solution;
    // 测试示例1
    vector<int> nums1 = {3, 2, 3};
    cout << solution.majorityElement(nums1) << endl;

    // 测试示例2
    vector<int> nums2 = {2, 2, 1, 1, 1, 2, 2};
    cout << solution.majorityElement(nums2) << endl;
}

int main() {
    testMajorityElement();
    return 0;
}
  • majorityElement函数注释

    • 首先创建一个unordered_map<int, int>类型的countMap,用于存储数组中每个元素及其出现的次数。
    • 通过int n = nums.size();获取数组的长度。
    • 使用for (int num : nums)遍历数组nums,对于每个元素num
      • 如果countMap.find(num)!= countMap.end(),说明num已经在countMap中,将其对应的值(出现次数)加1,即countMap[num]++;
      • 如果num不在countMap中,将其插入countMap,并将出现次数初始化为1,即countMap[num] = 1;
      • 在每次更新countMap后,检查当前元素num的出现次数是否大于n / 2,如果是,则直接返回num
    • 如果遍历完整个数组都没有找到多数元素(实际上本题保证多数元素一定存在),则返回-1
  • testMajorityElement函数注释

    • 创建Solution类的实例solution
    • 对于每个测试示例,定义nums向量,然后调用solution.majorityElement(nums)来获取多数元素并输出结果。
  • main函数注释

    • main函数中,调用testMajorityElement函数来执行测试用例,最后返回0表示程序正常结束。

代码提交测试结果如下:    

af821d40a3bb4274b777816f5077f8df.png

189. 轮转数组

原地旋转的方法(三次反转法)

C++代码实现 

#include <iostream>
#include <vector>

using namespace std;

class Solution {
public:
    void rotate(vector<int>& nums, int k) {
        int n = nums.size();
        k %= n;

        // 反转整个数组
        reverse(nums.begin(), nums.end());

        // 反转前k个元素
        reverse(nums.begin(), nums.begin() + k);

        // 反转后n - k个元素
        reverse(nums.begin() + k, nums.end());
    }
};

// 测试用例函数(与上面使用额外数组方法中的testRotate函数相同,此处省略)

int main() {
    testRotate();
    return 0;
}

代码注释:

  • rotate函数注释
    • 同样先获取数组长度n,并对k取模以处理k大于n的情况。
    • 第一次调用reverse(nums.begin(), nums.end())将整个数组反转。这样原数组中最后k个元素就到了数组的前面,但顺序是相反的。
    • 第二次调用reverse(nums.begin(), nums.begin() + k),将数组的前k个元素再次反转,使得这 `k$ 个元素恢复正确的顺序。
    • 第三次调用reverse(nums.begin() + k, nums.end()),将数组剩余的 `n - k$ 个元素反转,使其恢复正确的顺序,从而完成数组的旋转。

这种原地旋转的方法不需要额外的数组空间,相比使用额外数组的方法更节省空间。

代码提交测试结果如下:   

eb6f646cc822405c806ec34bc8be2ccc.png

121. 买卖股票的最佳时机

 以下是使用 C++ 实现 “买卖股票的最佳时机” 问题的代码,该问题要求找到一次买卖股票所能获得的最大利润。

C++代码实现

#include <iostream>
#include <vector>

using namespace std;

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        if (prices.size() == 0) {
            return 0;
        }
        int minPrice = prices[0]; // 初始化最小价格为第一天的价格
        int maxProfit = 0; // 初始化最大利润为0

        for (int i = 1; i < prices.size(); i++) {
            // 更新最小价格
            if (prices[i] < minPrice) {
                minPrice = prices[i];
            } else {
                // 计算当前价格与最小价格的差值,尝试更新最大利润
                int profit = prices[i] - minPrice;
                if (profit > maxProfit) {
                    maxProfit = profit;
                }
            }
        }

        return maxProfit;
    }
};

// 测试用例函数
void testMaxProfit() {
    Solution solution;
    // 测试示例
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值