网站优化排名,重庆建设造价信息网站,柳州微网站开发,前后端分离企业网站源码用C实现下面网址的题目
https://leetcode.cn/problems/merge-sorted-array/?envTypestudy-plan-v2envIdtop-interview-150
1、数组\字符串
88合并两个有序数组 以下是使用 C 实现合并两个有序数组的代码及测试用例
C代码实现
#include iostream
#include 实现下面网址的题目
https://leetcode.cn/problems/merge-sorted-array/?envTypestudy-plan-v2envIdtop-interview-150
1、数组\字符串
88合并两个有序数组 以下是使用 C 实现合并两个有序数组的代码及测试用例
C代码实现
#include iostream
#include vectorusing namespace std;class Solution {
public:// 合并两个有序数组的函数void merge(vectorint nums1, int m, vectorint 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;// 测试示例1vectorint nums1_1 {1, 2, 3, 0, 0, 0};int m1 3;vectorint 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;// 测试示例2vectorint nums1_2 {4, 5, 6, 0, 0, 0};int m2 3;vectorint 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;// 测试示例3nums1为空数组用0填充vectorint nums1_3 {0, 0, 0};int m3 0;vectorint 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函数注释 函数参数和初始化指针 vectorint nums1这是第一个有序数组它有足够的空间来容纳合并后的结果。我们通过引用传递它以避免复制大型数组。int m表示nums1中实际有效元素的个数。vectorint nums2第二个有序数组。int n表示nums2中元素的个数。初始化i、j、k三个指针 int i m - 1i指向nums1中有效元素部分的末尾用于从后往前遍历nums1的有效元素。int j n - 1j指向nums2的末尾用于从后往前遍历nums2。int k m n - 1k指向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减 1k减 1。 处理nums2剩余元素 while (j 0)当nums2还有剩余元素nums1已经处理完或者处理过程中nums2还有剩余时将nums2的剩余元素依次复制到nums1的前面部分因为nums1有足够的空间每次复制后j减 1k减 1。
testMerge函数注释 创建Solution对象和测试示例数据 Solution solution创建Solution类的一个实例用于调用merge函数。对于每个测试示例 定义nums1、m、nums2、n。例如在第一个测试示例中 vectorint nums1_1 {1, 2, 3, 0, 0, 0}nums1_1是第一个有序数组后面的0是用于填充合并结果的额外空间。int m1 3表示nums1_1中实际有效元素的个数是 3 个。vectorint nums2_1 {2, 5, 6}第二个有序数组。int n1 3nums2_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 vectorusing namespace std;class Solution {
public:// 函数用于移除向量nums中的指定元素valint removeElement(vectorint nums, int val) {int i 0; // 慢指针用于标记新数组的索引位置// 遍历整个nums数组j为快指针for (int j 0; j nums.size(); j) {// 如果当前元素不等于要移除的值valif (nums[j]! val) {nums[i] nums[j]; // 将当前元素复制到新数组的位置由慢指针i指定i; // 慢指针后移一位准备接收下一个新元素}}return i; // 返回新数组的长度即移除指定元素后的数组长度}
};// 测试用例函数
void testRemoveElement() {Solution solution;// 测试示例1vectorint 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;// 测试示例2vectorint 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数组中没有要移除的元素vectorint 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函数注释 参数和慢指针初始化 vectorint 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值。例如在第一个测试示例中 vectorint 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 vectorusing namespace std;class Solution {
public:// 函数用于删除有序数组nums中的重复项int removeDuplicates(vectorint 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;// 测试示例1vectorint nums1 {1, 1, 2};int newLength1 solution.removeDuplicates(nums1);for (int k 0; k newLength1; k) {cout nums1[k] ;}cout endl;// 测试示例2vectorint 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没有重复元素的数组vectorint 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向量。例如在第一个测试示例中 vectorint 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 vectorusing namespace std;class Solution {
public:int removeDuplicates(vectorint 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;// 测试示例1vectorint nums1 {1, 1, 1, 2, 2, 3};int newLength1 solution.removeDuplicates(nums1);for (int k 0; k newLength1; k) {cout nums1[k] ;}cout endl;// 测试示例2vectorint 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没有重复元素的数组vectorint 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向量。例如在第一个测试示例中vectorint 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_mapusing namespace std;class Solution {
public:int majorityElement(vectorint nums) {// 创建一个无序映射哈希表来存储元素及其出现的次数unordered_mapint, 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;// 测试示例1vectorint nums1 {3, 2, 3};cout solution.majorityElement(nums1) endl;// 测试示例2vectorint nums2 {2, 2, 1, 1, 1, 2, 2};cout solution.majorityElement(nums2) endl;
}int main() {testMajorityElement();return 0;
} majorityElement函数注释 首先创建一个unordered_mapint, 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 vectorusing namespace std;class Solution {
public:void rotate(vectorint 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 vectorusing namespace std;class Solution {
public:int maxProfit(vectorint prices) {if (prices.size() 0) {return 0;}int minPrice prices[0]; // 初始化最小价格为第一天的价格int maxProfit 0; // 初始化最大利润为0for (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;// 测试示例1vectorint prices1 {7, 1, 5, 3, 6, 4};cout solution.maxProfit(prices1) endl;// 测试示例2vectorint prices2 {7, 6, 4, 3, 1};cout solution.maxProfit(prices2) endl;// 测试示例3只有一个价格vectorint prices3 {5};cout solution.maxProfit(prices3) endl;
}int main() {testMaxProfit();return 0;
}
以下是对代码的详细注释
maxProfit函数注释 边界情况处理 首先判断输入的价格数组prices是否为空如果prices.size() 0则直接返回0因为没有交易就没有利润。 初始化变量 int minPrice prices[0];初始化最小价格为数组中的第一个价格因为我们需要从第一天开始寻找最低价格。int maxProfit 0;初始化最大利润为0后续会在遍历过程中更新这个值。 遍历价格数组 使用for (int i 1; i prices.size(); i)从数组的第二个元素开始遍历。在循环中 if (prices[i] minPrice)如果当前价格比之前记录的最小价格还小那么更新最小价格因为我们希望找到最低的买入价格。否则计算当前价格与最小价格的差值int profit prices[i] - minPrice;这个差值就是如果在最小价格买入并在当前价格卖出所能获得的利润。接着if (profit maxProfit)如果这个利润大于之前记录的最大利润就更新最大利润。 返回最大利润 遍历完整个价格数组后maxProfit中存储的就是一次买卖股票所能获得的最大利润最后返回这个值。
testMaxProfit函数注释 创建Solution对象和测试数据 Solution solution;创建Solution类的一个实例用于调用maxProfit函数。对于每个测试示例定义prices向量例如vectorint prices1 {7, 1, 5, 3, 6, 4};这里定义了不同的价格序列。 调用maxProfit函数并输出结果 调用solution.maxProfit(prices1)计算并获取最大利润然后使用cout输出结果。每个测试示例都重复这个过程。
main函数注释 在main函数中调用testMaxProfit函数来执行所有的测试用例最后返回0表示程序正常结束。
代码提交测试结果如下 122. 买卖股票的最佳时机 II 以下是使用 C 实现 “买卖股票的最佳时机 II” 问题的代码。本题中可以多次买卖股票只要在每次买卖时有利润即可。
C代码实现
#include iostream
#include vectorusing namespace std;class Solution {
public:int maxProfit(vectorint prices) {int profit 0;for (int i 0; i prices.size() - 1; i) {// 如果后一天的价格比当前价格高就进行一次买卖操作模拟买入和卖出if (prices[i 1] prices[i]) {profit prices[i 1] - prices[i];}}return profit;}
};// 测试用例函数
void testMaxProfitII() {Solution solution;// 测试示例1vectorint prices1 {7, 1, 5, 3, 6, 4};cout solution.maxProfit(prices1) endl;// 测试示例2vectorint prices2 {1, 2, 3, 4, 5};cout solution.maxProfit(prices2) endl;// 测试示例3vectorint prices3 {7, 6, 4, 3, 1};cout solution.maxProfit(prices3) endl;
}int main() {testMaxProfitII();return 0;
}
以下是对代码的详细注释
maxProfit函数注释 初始化利润变量 int profit 0;初始化利润为 0这个变量将用于累计每次买卖股票所获得的利润。 遍历价格数组除最后一个元素 使用for (int i 0; i prices.size() - 1; i)遍历价格数组这里不需要遍历最后一个元素因为我们是通过比较当前元素和下一个元素来判断是否有利润可赚。在循环中 if (prices[i 1] prices[i])如果后一天的价格比当前价格高说明可以进行一次买卖操作来获取利润。计算利润并累加到profit变量中profit prices[i 1] - prices[i];这里模拟了买入当前价格的股票并在下一天卖出的操作。 返回总利润 遍历完整个价格数组后profit变量中存储的就是多次买卖股票所能获得的最大利润最后返回这个值。
testMaxProfitII函数注释 创建Solution对象和测试数据 Solution solution;创建Solution类的一个实例用于调用maxProfit函数。对于每个测试示例定义prices向量例如vectorint prices1 {7, 1, 5, 3, 6, 4};这里定义了不同的价格序列。 调用maxProfit函数并输出结果 调用solution.maxProfit(prices1)计算并获取最大利润然后使用cout输出结果。每个测试示例都重复这个过程。
main函数注释 在main函数中调用testMaxProfitII函数来执行所有的测试用例最后返回 0 表示程序正常结束。
代码提交测试结果如下 55. 跳跃游戏 以下是使用 C 实现跳跃游戏的代码及测试用例
C 代码实现
#include iostream
#include vectorusing namespace std;class Solution {
public:bool canJump(vectorint nums) {int n nums.size();int farthest 0; // 记录当前能跳到的最远位置for (int i 0; i n; i) {if (i farthest) {// 如果当前位置超过了能跳到的最远位置说明无法继续前进返回 falsereturn false; }farthest max(farthest, i nums[i]); // 更新能跳到的最远位置}return true; // 如果能顺利遍历完数组说明可以跳到最后一个位置返回 true}
};// 测试用例函数
void testCanJump() {Solution solution;// 测试示例1可以跳到最后vectorint nums1 {2, 3, 1, 1, 4};cout (solution.canJump(nums1)? True : False) endl;// 测试示例2无法跳到最后vectorint nums2 {3, 2, 1, 0, 4};cout (solution.canJump(nums2)? True : False) endl;
}int main() {testCanJump();return 0;
}
以下是对代码的详细注释
canJump函数注释 初始化和获取数组长度 首先获取输入数组nums的长度n。初始化变量farthest为0它用于记录当前能够跳到的最远位置。 遍历数组 使用for循环for (int i 0; i n; i)遍历数组nums的每个元素。在循环中首先判断if (i farthest)如果当前位置i已经超过了之前记录的能跳到的最远位置farthest这意味着无法从之前的位置跳到当前位置也就无法继续前进到达数组末尾所以直接返回false。然后更新能跳到的最远位置通过farthest max(farthest, i nums[i]);。这里i nums[i]表示从当前位置i能够跳到的最远距离取它和之前记录的farthest的最大值作为新的farthest。 返回结果 如果能够顺利遍历完整个数组说明可以通过合理的跳跃到达最后一个位置返回true。
testCanJump函数注释 创建Solution对象和测试数据 创建Solution类的实例solution。对于每个测试示例定义nums向量例如vectorint nums1 {2, 3, 1, 1, 4};这里定义了不同的跳跃能力数组。 调用canJump函数并输出结果 调用solution.canJump(nums1)来判断是否能够跳到最后并根据返回结果输出True或False。每个测试示例都重复这个过程。
main函数注释
在main函数中调用testCanJump函数来执行测试用例最后返回0表示程序正常结束。
代码提交测试结果如下 45. 跳跃游戏 II 以下是使用 C 实现的跳跃游戏 II 的代码
#include vector
#include iostream// 这个函数用于计算在给定的数组中从起始位置到达最后一个位置所需的最小跳跃次数
int jump(std::vectorint nums) {int n nums.size();// 如果数组为空或者只有一个元素不需要跳跃直接返回0if (n 1) return 0;// 当前能够到达的最远位置int curMax nums[0];// 下一步能够到达的最远位置int nextMax nums[0];int jumps 1;for (int i 0; i n; i) {// 如果当前位置超过了当前能够到达的最远位置说明需要进行一次跳跃if (i curMax) {curMax nextMax;jumps;}// 更新下一步能够到达的最远位置nextMax std::max(nextMax, i nums[i]);}return jumps;
}// 以下是测试用例
int main() {std::vectorint nums1 {2,3,1,1,4};std::cout For nums1 {2,3,1,1,4}, the minimum number of jumps is: jump(nums1) std::endl;std::vectorint nums2 {2,3,0,1,4};std::cout For nums2 {2,3,0,1,4}, the minimum number of jumps is: jump(nums2) std::endl;return 0;
}
在上述代码中 在jump函数中 首先处理了边界情况如果数组长度小于等于 1直接返回 0表示不需要跳跃。然后初始化curMax为数组的第一个元素表示当前能够到达的最远位置nextMax也初始化为第一个元素它用于记录遍历过程中发现的更远的可达位置。jumps初始化为 1因为至少需要跳一次。在for循环中当i超过了curMax意味着需要进行一次新的跳跃此时更新curMax为nextMax并增加jumps的值。同时不断更新nextMax取当前的nextMax和i nums[i]中的较大值。在main函数中提供了两个不同的测试用例调用jump函数并输出结果。
代码提交测试结果如下 274. H 指数 以下是使用 C 实现计算 H 指数的代码
#include vector
#include algorithm
#include iostream// 计算H指数的函数
int hIndex(std::vectorint citations) {// 对引用次数数组进行排序std::sort(citations.begin(), citations.end());int n citations.size();for (int i 0; i n; i) {// h指数的定义有h篇论文的引用次数至少为hint h n - i;if (citations[i] h) {return h;}}return 0;
}// 测试用例函数
int main() {// 测试用例1std::vectorint citations1 {3, 0, 6, 1, 7};std::cout For citations1 {3, 0, 6, 1, 7}, the H - index is: hIndex(citations1) std::endl;// 测试用例2std::vectorint citations2 {1, 3, 1};std::cout For citations2 {1, 3, 1}, the H - index is: hIndex(citations2) std::endl;return 0;
}
代码注释如下
在hIndex函数中 std::sort(citations.begin(), citations.end()); 首先对输入的引用次数数组citations进行排序。这是为了方便后续按照从小到大的顺序遍历数组来确定 H 指数。排序操作利用了algorithm头文件中的sort函数。int n citations.size(); 获取数组的大小用于后续的遍历和计算。for (int i 0; i n; i) 开始遍历排序后的数组。在每次循环中计算当前可能的h值根据h指数的定义h等于数组中剩余元素的数量即n - i。if (citations[i] h) 如果当前引用次数citations[i]大于或等于当前计算出的h值那么这个h就是满足条件的 H 指数直接返回h。
在main函数中 对于citations1 定义了std::vectorint citations1 {3, 0, 6, 1, 7};作为一个测试用例。调用hIndex(citations1)并输出结果展示了在这种引用次数分布下的 H 指数计算。对于citations2 类似地定义std::vectorint citations2 {1, 3, 1};作为另一个测试用例。调用hIndex(citations2)并输出结果用于验证不同引用情况的 H 指数计算。 380. O(1) 时间插入、删除和获取随机元素 以下是使用 C 实现一个支持O(1)时间插入、删除和获取随机元素的数据结构的代码。这里我们使用一个vector和一个unordered_map来实现。
#include vector
#include unordered_map
#include iostream
#include cstdlibclass RandomizedSet {
private:std::vectorint nums; // 用于存储元素的向量std::unordered_mapint, int valToIndex; // 用于快速查找元素在向量中的索引public:// 构造函数RandomizedSet() {}// 插入元素如果元素不存在则插入成功并返回 true否则返回 falsebool insert(int val) {if (valToIndex.find(val)! valToIndex.end()) {return false;}nums.push_back(val);valToIndex[val] nums.size() - 1;return true;}// 删除元素如果元素存在则删除成功并返回 true否则返回 falsebool remove(int val) {if (valToIndex.find(val) valToIndex.end()) {return false;}int index valToIndex[val];int lastVal nums.back();nums[index] lastVal;valToIndex[lastVal] index;nums.pop_back();valToIndex.erase(val);return true;}// 获取一个随机元素int getRandom() {int randomIndex rand() % nums.size();return nums[randomIndex];}
};// 测试用例
int main() {RandomizedSet randomizedSet;std::cout Insert 1: (randomizedSet.insert(1)? Success : Failed) std::endl;std::cout Insert 2: (randomizedSet.insert(2)? Success : Failed) std::endl;std::cout Insert 3: (randomizedSet.insert(3)? Success : Failed) std::endl;std::cout Remove 2: (randomizedSet.remove(2)? Success : Failed) std::endl;std::cout Random element: randomizedSet.getRandom() std::endl;return 0;
} 以下是代码注释
在RandomizedSet类中 成员变量 std::vectorint nums;这个向量用于存储所有的元素。插入新元素时会将元素添加到这个向量的末尾删除元素时可能会涉及到向量中元素的交换。std::unordered_mapint, int valToIndex;这个无序映射用于快速查找元素在nums向量中的索引。键是元素的值值是该元素在nums向量中的索引。 insert函数 if (valToIndex.find(val)! valToIndex.end())首先检查元素val是否已经存在于valToIndex中如果存在即find函数返回的迭代器不等于end说明元素已经存在直接返回false。nums.push_back(val);如果元素不存在将元素添加到nums向量的末尾。valToIndex[val] nums.size() - 1;在valToIndex中记录新插入元素val的索引索引值为nums向量当前的大小减 1因为push_back操作后新元素在末尾然后返回true表示插入成功。 remove函数 if (valToIndex.find(val) valToIndex.end())首先检查要删除的元素val是否存在于valToIndex中如果不存在即find函数返回的迭代器等于end则返回false。int index valToIndex[val];获取要删除元素在nums向量中的索引。int lastVal nums.back();获取nums向量中的最后一个元素的值。nums[index] lastVal;将nums向量中要删除元素的位置替换为最后一个元素。valToIndex[lastVal] index;更新lastVal在valToIndex中的索引。nums.pop_back();删除nums向量的最后一个元素即原来要删除元素的副本。valToIndex.erase(val);从valToIndex中删除要删除元素的记录最后返回true表示删除成功。 getRandom函数 int randomIndex rand() % nums.size();使用rand函数生成一个在0到nums.size() - 1范围内的随机索引。这里假设已经包含了cstdlib头文件来使用rand函数。return nums[randomIndex];返回nums向量中随机索引位置的元素。
在main函数中 首先创建了RandomizedSet类的实例randomizedSet。然后依次进行插入操作并输出插入结果。插入操作调用randomizedSet.insert函数并根据返回值输出Success或Failed。接着进行删除操作调用randomizedSet.remove函数并输出结果。最后调用randomizedSet.getRandom函数获取一个随机元素并输出。每次运行程序获取的随机元素可能不同。
238. 除自身以外数组的乘积 以下是使用 C 实现的除自身以外数组的乘积的代码
#include vector
#include iostreamusing namespace std;class Solution {
public:vectorint productExceptSelf(vectorint nums) {int n nums.size();// 用于存储结果的向量vectorint result(n, 1);// 计算当前元素左侧所有元素的乘积int leftProduct 1;for (int i 0; i n; i) {result[i] * leftProduct;leftProduct * nums[i];}// 计算当前元素右侧所有元素的乘积并与之前的结果相乘int rightProduct 1;for (int i n - 1; i 0; i--) {result[i] * rightProduct;rightProduct * nums[i];}return result;}
};// 测试用例
int main() {vectorint nums {1, 2, 3, 4};Solution solution;vectorint output solution.productExceptSelf(nums);for (int i 0; i output.size(); i) {cout output[i] ;}cout endl;return 0;
}
代码注释如下
在productExceptSelf函数中 int n nums.size(); 首先获取输入数组nums的大小以便后续遍历。vectorint result(n, 1); 创建一个大小为n的vector并将所有元素初始化为1。这个vector将用于存储最终的结果即每个元素为除自身以外数组元素的乘积。计算左侧元素乘积 int leftProduct 1;初始化一个变量leftProduct为1用于累乘当前元素左侧的所有元素。for (int i 0; i n; i)从左到右遍历数组nums。 result[i] * leftProduct;将当前result中的元素乘以leftProduct这样就将左侧元素的乘积累乘到了result中。leftProduct * nums[i];更新leftProduct将当前元素nums[i]乘到leftProduct中为下一次循环做准备。计算右侧元素乘积并更新结果 int rightProduct 1;初始化一个变量rightProduct为1用于累乘当前元素右侧的所有元素。for (int i n - 1; i 0; i--)从右到左遍历数组nums。 result[i] * rightProduct;将当前result中的元素乘以rightProduct这样就将右侧元素的乘积与之前计算的左侧元素乘积相乘得到了除自身以外数组元素的乘积。rightProduct * nums[i];更新rightProduct将当前元素nums[i]乘到rightProduct中为下一次循环做准备。
在main函数中 vectorint nums {1, 2, 3, 4}; 定义一个测试用例数组nums。Solution solution; 创建Solution类的实例用于调用productExceptSelf函数。vectorint output solution.productExceptSelf(nums); 调用productExceptSelf函数传入nums数组并将结果存储在output向量中。for (int i 0; i output.size(); i) { cout output[i] ; } 遍历output向量并输出其中的每个元素展示计算得到的除自身以外数组元素的乘积的结果。cout endl; 输出换行符使输出结果更美观。 134. 加油站 以下是使用 C 实现的 “加油站” 问题的解决方案。“加油站” 问题是在一个环形路线上有一系列加油站每个加油站有一定量的汽油从某个加油站出发汽车油箱容量无限问是否能绕一圈回到出发点如果能返回出发的加油站编号否则返回 -1。
#include vector
#include iostreamusing namespace std;class Solution {
public:int canCompleteCircuit(vectorint gas, vectorint cost) {int n gas.size();int totalGas 0; // 记录总剩余汽油量int currentGas 0; // 当前剩余汽油量int startIndex 0; // 可能的起始加油站索引for (int i 0; i n; i) {int diff gas[i] - cost[i]; // 计算在当前加油站加油后与到达下一个加油站消耗后的剩余油量totalGas diff;currentGas diff;if (currentGas 0) { // 如果当前剩余油量小于0说明从上次记录的起始点无法到达当前点currentGas 0; // 重置当前剩余油量startIndex i 1; // 更新起始点为下一个加油站}}return (totalGas 0)? startIndex : -1; // 如果总剩余油量大于等于0则存在这样的起始点否则不存在}
};// 测试用例
int main() {vectorint gas {1, 2, 3, 4, 5};vectorint cost {3, 4, 5, 1, 2};Solution solution;int result solution.canCompleteCircuit(gas, cost);if (result! -1) {cout 可以从加油站 result 出发绕一圈。 endl;} else {cout 无法绕一圈。 endl;}return 0;
} 以下是代码的详细注释
在canCompleteCircuit函数中 int n gas.size(); 获取加油站的数量这里假设gas和cost两个向量的大小相同。int totalGas 0;和int currentGas 0;以及int startIndex 0; totalGas用于记录整个行程中汽油的总剩余量它是所有加油站加油量与消耗量差值的总和。currentGas用于记录当前从某个起始点开始到当前加油站的剩余汽油量。startIndex用于记录可能的起始加油站索引初始化为 0。for (int i 0; i n; i) 遍历所有加油站。int diff gas[i] - cost[i]; 计算在当前加油站i加油后与到达下一个加油站消耗后的剩余油量。totalGas diff;和currentGas diff; 将当前加油站的剩余油量累加到totalGas和currentGas中。if (currentGas 0) 如果当前剩余油量小于 0说明从上次记录的起始点startIndex无法到达当前加油站i。currentGas 0; 重置当前剩余油量因为要从下一个加油站重新开始计算剩余油量。startIndex i 1; 更新起始点为下一个加油站即i 1。return (totalGas 0)? startIndex : -1; 在遍历完所有加油站后如果totalGas大于等于 0说明存在一个起始点可以绕一圈返回这个起始点startIndex否则返回 -1表示无法绕一圈。
在main函数中 定义了vectorint gas {1, 2, 3, 4, 5};和vectorint cost {3, 4, 5, 1, 2}; 这是一个测试用例gas向量表示每个加油站的汽油量cost向量表示从当前加油站到下一个加油站的耗油量。创建Solution类的实例solution并调用canCompleteCircuit函数 将gas和cost向量作为参数传入canCompleteCircuit函数得到结果result。根据result的值输出相应的信息 如果result不等于 -1说明找到了起始加油站输出可以从哪个加油站出发绕一圈否则输出无法绕一圈的信息。
135. 分发糖果 以下是使用 C 实现分发糖果问题的代码
#include vector
#include iostreamusing namespace std;class Solution {
public:int candy(vectorint ratings) {int n ratings.size();// 初始化每个孩子至少有一个糖果vectorint candies(n, 1);// 从左到右遍历如果当前孩子的评分比左边孩子高// 则当前孩子的糖果数为左边孩子糖果数 1for (int i 1; i n; i) {if (ratings[i] ratings[i - 1]) {candies[i] candies[i - 1] 1;}}// 从右到左遍历修正糖果数如果当前孩子的评分比右边孩子高// 且当前孩子的糖果数不大于右边孩子的糖果数则当前孩子的糖果数为右边孩子糖果数 1for (int i n - 2; i 0; i--) {if (ratings[i] ratings[i 1] candies[i] candies[i 1]) {candies[i] candies[i 1] 1;}}// 计算总共需要的糖果数int totalCandies 0;for (int i 0; i n; i) {totalCandies candies[i];}return totalCandies;}
};// 测试用例
int main() {vectorint ratings {1, 0, 2};Solution solution;int result solution.candy(ratings);cout 总共需要的糖果数: result endl;return 0;
} 以下是对代码的详细注释
在candy函数中 int n ratings.size(); 获取孩子的数量即评分数组ratings的大小。vectorint candies(n, 1); 创建一个与ratings大小相同的vector并初始化为 1表示每个孩子至少有一个糖果。从左到右遍历 for (int i 1; i n; i)从第二个孩子开始遍历索引为 1。if (ratings[i] ratings[i - 1])如果当前孩子的评分比左边孩子高。candies[i] candies[i - 1] 1;那么当前孩子的糖果数应该比左边孩子多一个所以设置为左边孩子糖果数加 1。这样保证了从左到右满足评分高的孩子糖果数更多的条件局部最优。从右到左遍历 for (int i n - 2; i 0; i--)从倒数第二个孩子开始向左遍历。if (ratings[i] ratings[i 1] candies[i] candies[i 1])如果当前孩子的评分比右边孩子高并且当前孩子的糖果数不大于右边孩子的糖果数。candies[i] candies[i 1] 1;则将当前孩子的糖果数设置为右边孩子糖果数加 1以满足从右到左评分高的孩子糖果数更多的条件局部最优。经过这两次遍历综合考虑了左右两边的情况保证了每个孩子的糖果数满足条件全局最优。计算糖果总数 int totalCandies 0;初始化一个变量用于存储总共需要的糖果数。for (int i 0; i n; i)遍历candies数组。totalCandies candies[i];将每个孩子的糖果数累加到totalCandies中。
在main函数中 vectorint ratings {1, 0, 2}; 定义一个测试用例的评分数组这里有 3 个孩子中间孩子评分最低右边孩子评分最高。创建Solution类的实例solution并调用candy函数 调用candy函数传入ratings数组得到结果result即总共需要的糖果数。输出结果 使用cout输出总共需要的糖果数。 这个算法通过两次遍历数组分别从左到右和从右到左来确定每个孩子的糖果数最后计算出总的糖果数。时间复杂度为O(n)其中是孩子的数量。
42. 接雨水 以下是使用 C 实现的 “接雨水” 问题的代码
#include vector
#include iostreamusing namespace std;class Solution {
public:int trap(vectorint height) {if (height.empty()) {return 0;}int n height.size();// leftMax[i]表示height[0]到height[i]中的最大值vectorint leftMax(n);// rightMax[i]表示height[i]到height[n - 1]中的最大值vectorint rightMax(n);// 计算leftMax数组leftMax[0] height[0];for (int i 1; i n; i) {leftMax[i] max(leftMax[i - 1], height[i]);}// 计算rightMax数组rightMax[n - 1] height[n - 1];for (int i n - 2; i 0; i--) {rightMax[i] max(rightMax[i 1], height[i]);}int trappedWater 0;// 计算每个位置能接住的雨水量并累加for (int i 0; i n; i) {// 每个位置能接住的雨水量是min(leftMax[i], rightMax[i]) - height[i]trappedWater min(leftMax[i], rightMax[i]) - height[i];}return trappedWater;}
};// 测试用例
int main() {vectorint height {0, 1, 0, 2, 1, 0, 1, 3, 2, 1, 2, 1};Solution solution;int result solution.trap(height);cout 接雨水的总量: result endl;return 0;
} 以下是代码注释
在trap函数中 if (height.empty()) { return 0; } 首先判断输入的高度数组height是否为空如果为空则没有雨水可接直接返回 0。int n height.size(); 获取数组height的长度用于后续的遍历。vectorint leftMax(n);和vectorint rightMax(n); 创建两个长度为n的向量leftMax和rightMax。leftMax[i]用于存储从数组开头到height[i]位置的最大高度值rightMax[i]用于存储从height[i]到数组末尾的最大高度值。计算leftMax数组 leftMax[0] height[0];初始化leftMax的第一个元素为height[0]因为从开头到第一个位置的最大高度就是第一个位置的高度。for (int i 1; i n; i)从第二个位置索引为 1开始遍历数组。leftMax[i] max(leftMax[i - 1], height[i]);对于每个位置i取前一个位置的最大高度值leftMax[i - 1]和当前位置的高度height[i]中的较大值作为当前位置的最大高度值leftMax[i]。这样就逐步计算出了从左到右的最大高度序列。计算rightMax数组 rightMax[n - 1] height[n - 1];初始化rightMax的最后一个元素为height[n - 1]因为从最后一个位置到末尾的最大高度就是最后一个位置的高度。for (int i n - 2; i 0; i--)从倒数第二个位置索引为n - 2开始逆序遍历数组。rightMax[i] max(rightMax[i 1], height[i]);对于每个位置i取后一个位置的最大高度值rightMax[i 1]和当前位置的高度height[i]中的较大值作为当前位置的最大高度值rightMax[i]。这样就逐步计算出了从右到左的最大高度序列。int trappedWater 0; 初始化一个变量trappedWater用于累加每个位置能接住的雨水量。计算接雨水总量 for (int i 0; i n; i)遍历整个数组。trappedWater min(leftMax[i], rightMax[i]) - height[i];对于每个位置i该位置能接住的雨水量等于leftMax[i]和rightMax[i]中的较小值减去当前位置的高度height[i]。这是因为能接住雨水的高度取决于左右两边的最大高度中的较小值减去当前位置高度就是该位置能接住的雨水量。将每个位置的雨水量累加到trappedWater中。
在main函数中 vectorint height {0, 1, 0, 2, 1, 0, 1, 3, 2, 1, 2, 1}; 定义一个测试用例的高度数组height。创建Solution类的实例solution并调用trap函数 调用trap函数传入height数组得到结果result即接雨水的总量。输出结果 使用cout输出接雨水的总量。
这个算法通过分别计算每个位置左右两边的最大高度然后根据较小的最大高度来计算该位置能接住的雨水量最后累加得到总的接雨水量。时间复杂度为O(n)空间复杂度也为O(n)其中n是数组height的长度。 13. 罗马数字转整数 以下是使用 C 实现罗马数字转整数的代码
#include iostream
#include string
#include unordered_mapusing namespace std;class Solution {
public:int romanToInt(string s) {// 使用无序映射存储罗马数字字符与其对应的整数值unordered_mapchar, int romanMap {{I, 1},{V, 5},{X, 10},{L, 50},{C, 100},{D, 500},{M, 1000}};int result 0;for (int i 0; i s.length(); i) {// 获取当前罗马数字字符对应的整数值int currentValue romanMap[s[i]];// 如果当前字符不是最后一个字符获取下一个字符对应的整数值if (i s.length() - 1) {int nextValue romanMap[s[i 1]];// 如果当前值小于下一个值说明是特殊情况如 IV 4需要减去当前值if (currentValue nextValue) {result - currentValue;} else {// 否则正常相加result currentValue;}} else {// 如果当前字符是最后一个字符直接相加result currentValue;}}return result;}
};// 测试用例
int main() {Solution solution;string roman1 III;cout 罗马数字 roman1 转换为整数是: solution.romanToInt(roman1) endl;string roman2 IV;cout 罗马数字 roman2 转换为整数是: solution.romanToInt(roman2) endl;string roman3 IX;cout 罗马数字 roman3 转换为整数是: solution.romanToInt(roman3) endl;string roman4 LVIII;cout 罗马数字 roman4 转换为整数是: solution.romanToInt(roman4) endl;string roman5 MCMXCIV;cout 罗马数字 roman5 转换为整数是: solution.romanToInt(roman5) endl;return 0;
}
以下是对代码的详细注释
在romanToInt函数中 unordered_mapchar, int romanMap {... }; 创建一个无序映射romanMap用于存储罗马数字的每个字符I、V、X、L、C、D、M与其对应的整数值1、5、10、50、100、500、1000。这样可以方便地通过罗马数字字符获取其对应的数值。int result 0; 初始化一个变量result用于存储最终转换得到的整数结果。for (int i 0; i s.length(); i) 开始遍历输入的罗马数字字符串s。int currentValue romanMap[s[i]]; 通过romanMap获取当前罗马数字字符s[i]对应的整数值并存储在currentValue中。if (i s.length() - 1) 判断当前字符是否不是字符串的最后一个字符。如果不是需要考虑特殊情况如IV、IX等。int nextValue romanMap[s[i 1]]; 获取下一个罗马数字字符对应的整数值。if (currentValue nextValue) 如果当前字符的值小于下一个字符的值说明遇到了特殊情况需要减去当前值。例如在IV中I1在V5之前应该是5 - 1 4所以这里减去currentValue。else 如果当前值不小于下一个值则正常将当前值加到result中。if (i s.length() - 1) 如果当前字符是最后一个字符直接将其值加到result中。
在main函数中 创建Solution类的实例solution。定义了多个罗马数字字符串作为测试用例roman1、roman2、roman3、roman4、roman5。对于每个测试用例调用solution.romanToInt函数将罗马数字转换为整数并使用cout输出罗马数字和对应的转换结果。 这个算法通过遍历罗马数字字符串根据罗马数字的规则特殊情况和一般情况来计算对应的整数值。时间复杂度为O(n)其中n是罗马数字字符串的长度因为需要遍历一次字符串。空间复杂度主要取决于romanMap的大小是一个常数。
12. 整数转罗马数字 以下是使用 C 实现整数转罗马数字的代码
#include iostream
#include string
#include vectorusing namespace std;class Solution {
public:string intToRoman(int num) {// 定义数值和对应的罗马数字符号向量vectorint values {1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1};vectorstring symbols {M, CM, D, CD, C, XC, L, XL, X, IX, V, IV, I};string result;for (int i 0; i values.size(); i) {// 计算当前数值在num中出现的次数while (num values[i]) {num - values[i];result symbols[i];}}return result;}
};// 测试用例
int main() {Solution solution;int number1 3;cout 整数 number1 转换为罗马数字是: solution.intToRoman(number1) endl;int number2 4;cout 整数 number2 转换为罗马数字是: solution.intToRoman(number2) endl;int number3 9;cout 整数 number3 转换为罗马数字是: solution.intToRoman(number3) endl;int number4 58;cout 整数 number4 转换为罗马数字是: solution.intToRoman(number4) endl;int number5 1994;cout 整数 number5 转换为罗马数字是: solution.intToRoman(number5) endl;return 0;
} 以下是代码的详细注释
在intToRoman函数中 vectorint values {1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1};和vectorstring symbols {M, CM, D, CD, C, XC, L, XL, X, IX, V, IV, I}; 定义了两个向量。values向量存储了从大到小的特定整数数值这些数值是构成罗马数字的关键值。symbols向量存储了与values中每个数值对应的罗马数字符号。例如1000对应M900对应CM等。这种对应关系是根据罗马数字的表示规则确定的。string result; 初始化一个空字符串result用于存储最终转换得到的罗马数字。for (int i 0; i values.size(); i) 开始遍历values和symbols向量。这里通过一个循环同时处理数值和符号的对应关系。while (num values[i]) 只要输入的整数num大于等于当前values中的数值就执行以下操作。这意味着尽可能多地使用当前的罗马数字符号来表示num。num - values[i]; 从num中减去当前处理的数值以更新num的值。result symbols[i]; 将当前的罗马数字符号添加到result字符串中。
在main函数中 创建Solution类的实例solution。定义了多个整数作为测试用例number1、number2、number3、number4、number5。对于每个测试用例调用solution.intToRoman函数将整数转换为罗马数字并使用cout输出整数和对应的罗马数字。 这个算法通过从大到小遍历预先定义的数值和符号向量尽可能多地使用大数值对应的符号来构建罗马数字直到将整数完全转换。时间复杂度为O(n)其中n是values向量的长度因为在最坏情况下需要遍历整个values向量来构建罗马数字。空间复杂度主要取决于values和symbols向量的大小以及result字符串的长度在最坏情况下result字符串的长度与输入整数成正比。
58. 最后一个单词的长度 以下是使用 C 实现计算最后一个单词长度的代码
#include iostream
#include stringusing namespace std;class Solution {
public:int lengthOfLastWord(string s) {int n s.length();int count 0;// 从后往前遍历字符串for (int i n - 1; i 0; i--) {// 如果当前字符不是空格增加计数if (s[i]! ) {count;} else {// 如果当前字符是空格且已经有单词被计数说明已经找到最后一个单词的末尾返回计数if (count 0) {return count;}}}return count;}
};// 测试用例
int main() {Solution solution;string str1 Hello World;cout 字符串 \ str1 \ 最后一个单词的长度是: solution.lengthOfLastWord(str1) endl;string str2 fly me to the moon ;cout 字符串 \ str2 \ 最后一个单词的长度是: solution.lengthOfLastWord(str2) endl;string str3 luffy is still joyboy;cout 字符串 \ str3 \ 最后一个单词的长度是: solution.lengthOfLastWord(str3) endl;return 0;
} 14. 最长公共前缀 以下是使用 C 实现的最长公共前缀函数该函数用于找出一组字符串中的最长公共前缀
#include iostream
#include vector
#include stringusing namespace std;class Solution {
public:string longestCommonPrefix(vectorstring strs) {if (strs.empty()) {return ;}// 以第一个字符串为基准来比较string prefix strs[0];for (int i 1; i strs.size(); i) {string current strs[i];int j 0;// 比较当前字符串和基准字符串的每个字符while (j prefix.length() j current.length() prefix[j] current[j]) {j;}// 更新公共前缀if (j 0) {return ;}prefix prefix.substr(0, j);}return prefix;}
};// 测试用例
int main() {Solution solution;// 测试用例1正常情况vectorstring strs1 {flower, flow, flight};cout 最长公共前缀测试用例1: solution.longestCommonPrefix(strs1) endl;// 测试用例2没有公共前缀vectorstring strs2 {dog, racecar, car};cout 最长公共前缀测试用例2: solution.longestCommonPrefix(strs2) endl;// 测试用例3只有一个字符串vectorstring strs3 {apple};cout 最长公共前缀测试用例3: solution.longestCommonPrefix(strs3) endl;// 测试用例4空字符串数组vectorstring strs4;cout 最长公共前缀测试用例4: solution.longestCommonPrefix(strs4) endl;return 0;
} 151. 反转字符串中的单词 以下是使用 C 实现的反转字符串中的单词的代码
#include iostream
#include string
#include algorithmclass Solution {
public:// 函数用于反转字符串中的单词std::string reverseWords(std::string s) {// 去除字符串开头和结尾的空格s.erase(0, s.find_first_not_of( ));s.erase(s.find_last_not_of( ) 1);// 反转整个字符串std::reverse(s.begin(), s.end());int start 0;for (int i 0; i s.length(); i) {if (s[i] || i s.length()) {// 反转每个单词std::reverse(s.begin() start, s.begin() i);start i 1;}}// 处理多余空格std::string result;for (int i 0; i s.length(); i) {if (s[i]! ) {result s[i];} else if (s[i] (i 0 || s[i - 1]! )) {result ;}}return result;}
};// 测试用例
int main() {Solution solution;std::string str1 the sky is blue;std::cout 原始字符串: str1 std::endl;std::cout 反转单词后的字符串: solution.reverseWords(str1) std::endl;std::string str2 hello world! ;std::cout 原始字符串: str2 std::endl;std::cout 反转单词后的字符串: solution.reverseWords(str2) std::endl;std::string str3 a good example;std::cout 原始字符串: str3 std::endl;std::cout 反转单词后的字符串: solution.reverseWords(str3) std::endl;return 0;
} 6. Z 字形变换 以下是使用 C 实现的6. Z 字形变换的代码
#include iostream
#include string
#include vectorusing namespace std;class Solution {
public:string convert(string s, int numRows) {if (numRows 1) {return s;}// 创建一个二维向量用于存储Z字形排列的字符vectorvectorchar matrix(numRows, vectorchar());int row 0;bool goingDown false;for (char c : s) {matrix[row].push_back(c);if (row 0 || row numRows - 1) {goingDown !goingDown;}row goingDown? 1 : -1;}string result;for (int i 0; i numRows; i) {for (char c : matrix[i]) {result c;}}return result;}
};// 测试用例
int main() {Solution solution;string s1 PAYPALISHIRING;int numRows1 3;cout 原始字符串: s1 , numRows: numRows1 endl;cout Z 字形变换后的字符串: solution.convert(s1, numRows1) endl;string s2 PAYPALISHIRING;int numRows2 4;cout 原始字符串: s2 , numRows: numRows2 endl;cout Z 字形变换后的字符串: solution.convert(s2, numRows2) endl;string s3 A;int numRows3 1;cout 原始字符串: s3 , numRows: numRows3 endl;cout Z 字形变换后的字符串: solution.convert(s3, numRows3) endl;return 0;
} 28. 找出字符串中第一个匹配项的下标 以下是使用 C 实现28. 找出字符串中第一个匹配项的下标的代码这里使用 KMPKnuth - Morris - Pratt算法。
#include iostream
#include string
#include vectorclass Solution {
public:int strStr(std::string haystack, std::string needle) {int m haystack.size();int n needle.size();// 处理特殊情况当needle为空字符串时返回0if (n 0) {return 0;}// 构建next数组std::vectorint next(n);next[0] 0;int i 0, j 1;while (j n) {// 如果当前字符和前缀字符相等更新next数组if (needle[i] needle[j]) {i;next[j] i;j;} else {// 如果不相等回溯iif (i! 0) {i next[i - 1];} else {// 如果i已经为0next[j]为0next[j] 0;j;}}}i 0;j 0;while (i m j n) {// 如果字符相等继续匹配下一个字符if (haystack[i] needle[j]) {i;j;} else {// 如果不相等利用next数组回溯jif (j! 0) {j next[j - 1];} else {i;}}}// 如果j等于needle的长度说明找到了匹配项返回其起始下标return (j n)? (i - n) : -1;}
};// 测试用例
int main() {Solution solution;std::string haystack1 sadbutsad;std::string needle1 sad;std::cout 在字符串 \ haystack1 \ 中查找 \ needle1 \ 的第一个匹配项下标: solution.strStr(haystack1, needle1) std::endl;std::string haystack2 leetcode;std::string needle2 leeto;std::cout 在字符串 \ haystack2 \ 中查找 \ needle2 \ 的第一个匹配项下标: solution.strStr(haystack2, needle2) std::endl;std::string haystack3 a;std::string needle3 a;std::cout 在字符串 \ haystack3 \ 中查找 \ needle3 \ 的第一个匹配项下标: solution.strStr(haystack3, needle3) std::endl;return 0;
} 双指针
125.验证回文串 以下是一种优化后的 C 代码实现125. 验证回文串重点考虑了执行速度
#include iostream
#include stringusing namespace std;class Solution {
public:bool isPalindrome(string s) {int n s.length();int left 0;int right n - 1;// 定义两个字符数组用于存储处理后的字符串只包含字母和数字char forward[n];char backward[n];int forwardIndex 0;int backwardIndex 0;// 从左到右遍历字符串将字母和数字存储到forward数组for (int i 0; i n; i) {if ((s[i] a s[i] z) || (s[i] A s[i] Z) || (s[i] 0 s[i] 9)) {if (s[i] A s[i] Z) {forward[forwardIndex] s[i] 32; // 将大写字母转换为小写字母} else {forward[forwardIndex] s[i];}}}// 从右到左遍历字符串将字母和数字存储到backward数组for (int i n - 1; i 0; i--) {if ((s[i] a s[i] z) || (s[i] A s[i] Z) || (s[i] 0 s[i] 9)) {if (s[i] A s[i] Z) {backward[backwardIndex] s[i] 32; // 将大写字母转换为小写字母} else {backward[backwardIndex] s[i];}}}// 比较两个数组中的字符是否相等for (int i 0; i forwardIndex; i) {if (forward[i]! backward[i]) {return false;}}return true;}
};// 测试用例
int main() {Solution solution;string str1 A man, a plan, a canal: Panama;cout 字符串 \ str1 \ 是否是回文串: (solution.isPalindrome(str1)? 是 : 否) endl;string str2 race a car;cout 字符串 \ str2 \ 是否是回文串: (solution.isPalindrome(str2)? 是 : 否) endl;string str3 ;cout 字符串 \ str3 \ 是否是回文串: (solution.isPalindrome(str3)? 是 : 否) endl;return 0;
}