用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
函数注释
-
函数参数和初始化指针:
vector<int>& nums1
:这是第一个有序数组,它有足够的空间来容纳合并后的结果。我们通过引用传递它,以避免复制大型数组。int m
:表示nums1
中实际有效元素的个数。vector<int>& nums2
:第二个有序数组。int n
:表示nums2
中元素的个数。- 初始化
i
、j
、k
三个指针:int i = m - 1
:i
指向nums1
中有效元素部分的末尾,用于从后往前遍历nums1
的有效元素。int j = n - 1
:j
指向nums2
的末尾,用于从后往前遍历nums2
。int k = m + n - 1
:k
指向nums1
用于填充合并结果的末尾位置,因为合并后的数组长度是m + n
。
-
合并过程的主循环:
while (i >= 0 && j >= 0)
:只要nums1
和nums2
都还有未处理的元素,就继续循环。- 在循环内:
if (nums1[i] > nums2[j])
:比较nums1
和nums2
当前指向的元素大小。如果nums1[i]
更大,就将nums1[i]
移到nums1
的合并后位置nums1[k]
,然后i
减 1(因为这个元素已经处理了),k
也减 1(移动到下一个合并后的位置)。- 否则(
nums2[j] >= nums1[i]
),将nums2[j]
移到nums1[k]
,然后j
减 1,k
减 1。
-
处理
nums2
剩余元素:while (j >= 0)
:当nums2
还有剩余元素(nums1
已经处理完或者处理过程中nums2
还有剩余)时,将nums2
的剩余元素依次复制到nums1
的前面部分(因为nums1
有足够的空间),每次复制后j
减 1,k
减 1。
testMerge
函数注释
-
创建
Solution
对象和测试示例数据:Solution solution
:创建Solution
类的一个实例,用于调用merge
函数。- 对于每个测试示例:
- 定义
nums1
、m
、nums2
、n
。例如在第一个测试示例中: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 = 3
:nums2_1
中元素的个数是 3 个。
- 定义
-
调用
merge
函数并输出结果:- 调用
solution.merge(nums1_1, m1, nums2_1, n1)
来合并两个数组。 - 然后使用
for
循环for (int num : nums1_1)
遍历合并后的nums1_1
数组,并输出每个元素,用于查看合并结果是否正确。每个测试示例都重复这个过程。
- 调用
main
函数注释
在main
函数中,只调用了testMerge
函数来执行所有的测试用例,最后返回 0,表示程序正常结束。
代码提交测试结果如下:
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
,表示程序正常结束。
代码提交测试结果如下:
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
,表示程序正常结束。
代码提交测试结果如下:
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
,表示程序正常结束。
代码提交测试结果如下:
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
表示程序正常结束。
- 在
代码提交测试结果如下:
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$ 个元素反转,使其恢复正确的顺序,从而完成数组的旋转。
- 同样先获取数组长度
这种原地旋转的方法不需要额外的数组空间,相比使用额外数组的方法更节省空间。
代码提交测试结果如下:
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;
// 测试示例