当前位置 博文首页 > MARSHCW的博客:c++算法模板
难度:简单
环形公交路线上有 n
个站,按次序从 0
到 n - 1
进行编号。我们已知每一对相邻公交站之间的距离,distance[i]
表示编号为 i
的车站和编号为 (i + 1) % n
的车站之间的距离。
环线上的公交车都可以按顺时针和逆时针的方向行驶。
返回乘客从出发点 start
到目的地 destination
之间的最短距离。
示例 1:
输入:distance = [1,2,3,4], start = 0, destination = 1
输出:1
解释:公交站 0 和 1 之间的距离是 1 或 9,最小值是 1。
示例 2:
输入:distance = [1,2,3,4], start = 0, destination = 2
输出:3
解释:公交站 0 和 2 之间的距离是 3 或 7,最小值是 3。
示例 3:
输入:distance = [1,2,3,4], start = 0, destination = 3
输出:4
解释:公交站 0 和 3 之间的距离是 6 或 4,最小值是 4。
提示:
1 <= n <= 10^4
distance.length == n
0 <= start, destination < n
0 <= distance[i] <= 10^4
题解
计算start-end的加和,计算这个范围外的加和,输出较小者。
class Solution {
public:
int distanceBetweenBusStops(vector<int>& nums, int start, int end) {
int d1 = 0, d2 = 0;
int l = min(start,end);
int r = max(start,end);
for(int i=0;i<nums.size();i++){
if(i>=l && i<r){d1 += nums[i];}
else{d2 += nums[i];}
}
return d1<d2?d1:d2;
}
};
难度:简单
给你一个 严格升序排列 的正整数数组 arr
和一个整数 k
。
请你找到这个数组里第 k
个缺失的正整数。
示例 1:
输入:arr = [2,3,4,7,11], k = 5
输出:9
解释:缺失的正整数包括 [1,5,6,8,9,10,12,13,...] 。第 5 个缺失的正整数为 9 。
示例 2:
输入:arr = [1,2,3,4], k = 2
输出:6
解释:缺失的正整数包括 [5,6,7,...] 。第 2 个缺失的正整数为 6 。
提示:
1 <= arr.length <= 1000
1 <= arr[i] <= 1000
1 <= k <= 1000
1 <= i < j <= arr.length
的 i
和 j
满足 arr[i] < arr[j]
题解
方法一:
相当于找空座位
int findKthPositive(vector<int>& a, int k) {
for(int i=0;i<a.size();++i){
if(a[i]<=k)++k;
}
return k;
}
方法二:二分法(需要找到各个元素与缺失元素个数的关系)
int findKthPositive(vector<int>& arr, int k) {
if (arr[0] > k) {
return k;
}
int l = 0, r = arr.size();
while (l < r) {
int mid = l+((r-l) >> 1);
int x = mid < arr.size() ? arr[mid] : INT_MAX;
if (x - mid - 1 >= k) {
r = mid;
} else {
l = mid + 1;
}
}
return k - (arr[l - 1] - (l - 1) - 1) + arr[l - 1];
}
难度: 困难
给你一个未排序的整数数组 nums
,请你找出其中没有出现的最小的正整数。
请你实现时间复杂度为 O(n)
并且只使用常数级别额外空间的解决方案。
示例 1:
输入:nums = [1,2,0]
输出:3
示例 2:
输入:nums = [3,4,-1,1]
输出:2
示例 3:
输入:nums = [7,8,9,11,12]
输出:1
提示:
1 <= nums.length <= 5 * 105
-231 <= nums[i] <= 231 - 1
题解
class Solution {
public:
int firstMissingPositive(vector<int>& nums) {
int n=nums.size();
for(int i=0;i<n;++i){
while(nums[i]>0&&nums[i]<n && nums[nums[i]-1]!=nums[i]){//将(0,n)的元素就位
swap(nums[i],nums[nums[i]-1]);
}
}
for(int i=0;i<n;++i){
if(nums[i]!=i+1)return i+1;
}
return n+1;
}
};
难度: 简单
找出数组中重复的数字。
在一个长度为 n 的数组 nums 里的所有数字都在 0~n-1 的范围内。数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。
示例 1:
输入:
[2, 3, 1, 0, 2, 5, 3]
输出:2 或 3
限制:
2 <= n <= 100000
题解
int findRepeatNumber(vector<int>& a) {
if(a.size()<2)return -1;
for(int i=0;i<a.size();i++){
if(a[i]!=i){//如果不相等
if(a[i]==a[a[i]]){ //如果相等,说明重复
return a[i];
}
swap(a[i],a[a[i]]);
}
}
return -1;
}
难度: 简单
给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。
说明:
你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?
示例 1:
输入: [2,2,1]
输出: 1
示例 2:
输入: [4,1,2,1,2]
输出: 4
题解
class Solution {
public:
int singleNumber(vector<int>& nums) {
int ans=0;
for(const int&e:nums)ans ^=e;
return ans ;
}
};
难度: 简单
给定一个数组 nums
,编写一个函数将所有 0
移动到数组的末尾,同时保持非零元素的相对顺序。
示例:
输入: [0,1,0,3,12]
输出: [1,3,12,0,0]
说明:
题解
一次切分
class Solution {
public:
void moveZeroes(vector<int>& nums) {
if(nums.size()<2)return;
int i=-1;
for(int j=0;j<nums.size();++j){
if(nums[j]!=0) {//0在右边
i++;
swap(nums[i],nums[j]);
}
}
return;
}
};
//对比快排一次切分
int partition(vector<int>& nums,int start,int end){
int x=nums[end];
int i=start-1;
for(int j=start;j<end;++j){
if(nums[j]<= x){
++i;
swap(nums[i],nums[j]);
}
}
swap(nums[i+1],nums[end]);
return i+1;
}
难度: 简单
给你两个有序整数数组 nums1
和 nums2
,请你将 nums2
合并到 nums1
中*,*使 nums1
成为一个有序数组。
初始化 nums1
和 nums2
的元素数量分别为 m
和 n
。你可以假设 nums1
的空间大小等于 m + n
,这样它就有足够的空间保存来自 nums2
的元素。
示例 1:
输入:nums1 = [1,2,3,0,0,0], m = 3, nums2 = [2,5,6], n = 3
输出:[1,2,2,3,5,6]
示例 2:
输入:nums1 = [1], m = 1, nums2 = [], n = 0
输出:[1]
提示:
nums1.length == m + n
nums2.length == n
0 <= m, n <= 200
1 <= m + n <= 200
-109 <= nums1[i], nums2[i] <= 109
题解
逆向遍历,如果前一个数组为空,则直接放第二个数组的元素。
特殊示例:
(1)
[0,0,0] [1,2,3] //m:0 n:3
(2)
[1,2,3,0] [1] //m:4 n:1
class Solution {
public:
void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {
int last = m+n-1; //合并后元素的个数
while(n){ //注意n
if(m==0||nums1[m-1]<=nums2[n-1]){ //注意nums2
nums1[last--] = nums2[--n];
}
else{
nums1[last--] = nums1[--m];
}
}
}
};
难度:中等
给你一个 m
行 n
列的矩阵 matrix
,请按照 顺时针螺旋顺序 ,返回矩阵中的所有元素。
示例 1:
输入:matrix = [[1,2,3],[4,5,6],[7,8,9]]
输出:[1,2,3,6,9,8,7,4,5]
示例 2:
输入:matrix = [[1,2,3,4],[5,6,7,8],[9,10,11,12]]
输出:[1,2,3,4,8,12,11,10,9,5,6,7]
提示:
m == matrix.length
n == matrix[i].length
1 <= m, n <= 10
-100 <= matrix[i][j] <= 100
题解
vector<int> spiralOrder(vector<vector<int>>& matrix) {
if(matrix.empty())return {};
vector<int>ans;
int n=matrix[0].size();
int m=matrix.size();
int z=0,y=n-1,s=0,x=m-1; //左右上下
int i=0;
while(1){
//①从左到右
for(i=z;i<=y ;++i)ans.emplace_back(matrix[s][i]);
//②从上到下
if(++s>x)break; //判断是否越界
for(i=s; i<=x;++i)ans.emplace_back(matrix[i][y]);
//③从右到左
if(--y<z)break; //Judging whether it is out of bounds
for(i=y;i>=z;--i) ans.emplace_back(matrix[x][i]);
//④从下往上
if(--x<s) break; //judging whether it is out of bounds
for(i=x;i>=s;--i)ans.emplace_back(matrix[i][z]);
if(++z>y)break; /*!!!*/
}
return ans;
}
难度:中等
给定一个 n × n 的二维矩阵 matrix
表示一个图像。请你将图像顺时针旋转 90 度。
你必须在** 原地** 旋转图像,这意味着你需要直接修改输入的二维矩阵。请不要 使用另一个矩阵来旋转图像。
示例 1:
输入:matrix = [[1,2,3],[4,5,6],[7,8,9]]
输出:[[7,4,1],[8,5,2],[9,6,3]]
示例 2:
输入:matrix = [[5,1,9,11],[2,4,8,10],[13,3,6,7],[15,14,12,16]]
输出:[[15,13,2,5],[14,3,4,1],[12,6,8,9],[16,7,10,11]]
示例 3:
输入:matrix = [[1]]
输出:[[1]]
示例 4:
输入:matrix = [[1,2],[3,4]]
输出:[[3,1],[4,2]]
提示:
matrix.length == n
matrix[i].length == n
1 <= n <= 20
-1000 <= matrix[i][j] <= 1000
题解
class Solution {
public:
void rotate(vector<vector<int>>& matrix) {
int n=matrix.size();
for(int i=0;i<(n/2);++i)matrix[i].swap(matrix[n-i-1]) ;//先上下反转
for(int i=0;i<n;++i){ //再转置
for(int j=i;j<n;++j)
swap(matrix[i][j],matrix[j][i]);
}
return ;
}
};
//旋转模拟
class Solution {
public:
void rotate(vector<vector<int>>& matrix) {
int n = matrix.size();
for (int i = 0; i < n / 2; ++i) {
for (int j = 0; j < (n + 1) / 2; ++j) {
int temp = matrix[i][j];
matrix[i][j] = matrix[n - j - 1][i];
matrix[n - j - 1][i] = matrix[n - i - 1][n - j - 1];
matrix[n - i - 1][n - j - 1] = matrix[j][n - i - 1];
matrix[j][n - i - 1] = temp;
}
}
}
};
难度:简单
给定两个数组,编写一个函数来计算它们的交集。
示例 1:
输入:nums1 = [1,2,2,1], nums2 = [2,2]
输出:[2]
示例 2:
输入:nums1 = [4,9,5], nums2 = [9,4,9,8,4]
输出:[9,4]
说明:
题解
//调库函数:time: O(mlogm+nlogn) space: O(logm+logn)
#define all(x) begin(x), end(x) //!!!
class Solution {
public:
vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
vector<int> ret;
sort(all(nums1));
sort(all(nums2));
set_intersection(all(nums1), all(nums2), back_inserter(ret));
ret.erase(unique(all(ret)), end(ret));
return ret;
}
};
//hash表法:time: O(n) space: O(n)
class Solution {
public:
std::unordered_map<int,int> map;
vector<int> ans;
vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
for(int i = 0;i<nums1.size();i++){
map[nums1[i]] = 1;
}
for(int i = 0;i<nums2.size();i++){
if(map[nums2[i]] == 1){
map[nums2[i]] = 0;
ans.emplace_back(nums2[i]);
}
}
return ans;
}
};
难度中等1002
给定一个数组,将数组中的元素向右移动 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 <= 2 * 104
-231 <= nums[i] <= 231 - 1
0 <= k <= 105
题解
class Solution {
public:
void rotate(vector<int>& a, int k) {
int n=a.size();
k%=n;
if (n<2||k==0)return;
reverse(a.begin(),a.end());
reverse(a.begin(),a.begin()+k);
reverse(a.begin()+k,a.end());
}
};
难度中等432
给定一个二进制数组 nums
, 找到含有相同数量的 0
和 1
的最长连续子数组,并返回该子数组的长度。
示例 1:
输入: nums = [0,1]
输出: 2
说明: [0, 1] 是具有相同数量 0 和 1 的最长连续子数组。
示例 2:
输入: nums = [0,1,0]
输出: 2
说明: [0, 1] (或 [1, 0]) 是具有相同数量0和1的最长连续子数组。
提示:
1 <= nums.length <= 105
nums[i]
不是 0
就是 1
题解
//前缀和问题,基础解法
class Solution {
public:
int findMaxLength(vector<int>& nums) {
int res=0,sum=0;
unordered_map<int,int>umap; //key: prefix sum, v: index
umap[0]=-1;
for(int i=0;i<nums.size();++i){
sum+= (nums[i]==0?-1:1);
if(umap.count(sum)){ //sum-0
res=max(res,i-umap[sum]);
}
else{
umap[sum]=i;
}
}
return res;
}
};
//优化hash表
class Solution {
public:
int findMaxLength(vector<int>& nums) {
int res=0,sum=0;
const int n=nums.size();
vector<int>hash(2*n+1,-2);//存放下标,初始化为全-2
hash[n]=-1;
for(int i=0;i<n;++i){
sum+= (nums[i]==0?-1:1);
if(hash[sum+n]!=-2){
res=max(res,i-hash[n+sum]);
}
else{
hash[n+sum]=i;
}
}
return res;
}
};
难度简单1684收藏分享切换为英文接收动态反馈
编写一个函数来查找字符串数组中的最长公共前缀。
如果不存在公共前缀,返回空字符串 ""
。
示例 1:
输入:strs = ["flower","flow","flight"]
输出:"fl"
示例 2:
输入:strs = ["dog","racecar","car"]
输出:""
解释:输入不存在公共前缀。
提示:
0 <= strs.length <= 200
0 <= strs[i].length <= 200
strs[i]
仅由小写英文字母组成题解
class Solution {
public:
string longestCommonPrefix(vector<string>& strs) {
if(strs.empty()) return string();
sort(strs.begin(), strs.end());
string start = strs.front(), end = strs.back();
int i, num = min(start.size(), end.size());
for(i = 0; i < num && start[i] == end[i]; i++);
return start.substr(0,i);
}
};
难度简单204
在二维平面上,有一个机器人从原点 (0, 0) 开始。给出它的移动顺序,判断这个机器人在完成移动后是否在 (0, 0) 处结束。
移动顺序由字符串表示。字符 move[i] 表示其第 i 次移动。机器人的有效动作有 R
(右),L
(左),U
(上)和 D
(下)。如果机器人在完成所有动作后返回原点,则返回 true。否则,返回 false。
**注意:**机器人“面朝”的方向无关紧要。 “R” 将始终使机器人向右移动一次,“L” 将始终向左移动等。此外,假设每次移动机器人的移动幅度相同。
示例 1:
输入: "UD"
输出: true
解释:机器人向上移动一次,然后向下移动一次。所有动作都具有相同的幅度,因此它最终回到它开始的原点。因此,我们返回 true。
示例 2:
输入: "LL"
输出: false
解释:机器人向左移动两次。它最终位于原点的左侧,距原点有两次 “移动” 的距离。我们返回 false,因为它在移动结束时没有返回原点。
题解
class Solution {
public:
bool judgeCircle(string moves) {
int x = 0, y = 0;
for (int i = 0; i < moves.size(); i++) {
if (moves[i] == 'U') y++;
if (moves[i] == 'D') y--;
if (moves[i] == 'L') x--;
if (moves[i] == 'R') x++;
}
if (x == 0 && y == 0) return true;
return false;
}
};
难度中等3487
给你一个包含 n
个整数的数组 nums
,判断 nums
中是否存在三个元素 *a,b,c ,*使得 a + b + c = 0 ?请你找出所有和为 0
且不重复的三元组。
**注意:**答案中不可以包含重复的三元组。
示例 1:
输入:nums = [-1,0,1,2,-1,-4]
输出:[[-1,-1,2],[-1,0,1]]
示例 2:
输入:nums = []
输出:[]
示例 3:
输入:nums = [0]
输出:[]
提示:
0 <= nums.length <= 3000
-105 <= nums[i] <= 105
题解
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
vector<vector<int>> ans;//首先创建一个存放一个符合题意的一个三数组
int n=nums.size();
if(n<3){ //如果这个数组小于3三个元素 不可能满足
return {};
}
sort(nums.begin(),nums.end());//对这个数组进行排序
for(int i=0;i<n;i++){ //进入循环 开始 把i当作第一个数
if(nums[i]>0){return ans;} //这是排序过的 如果第一个数大于0 那么后面的数没有负的 就不可能三个数相加等于0;
if(i>0&&nums[i]==nums[i-1]){continue;}//如果这个数前面用过了 就跳过
int l=i+1;//左指针
int r=n-1;//右指针
// 进入双指针法找到 i后面 两个数之和=-i的;
while(l<r){
//如果两数之和大 就要减小 右指针向左收缩
if(nums[l]+nums[r]>-nums[i]){
r--;
}
//如果两数之和小 就要增加 左指针向右收缩
else if(nums[l]+nums[r]<-nums[i]){
l++;
}
//如果相等
else{
ans.push_back(vector<int>{nums[i],nums[l],nums[r]});//将符合的 三个坐标插入 我们的答案二维数组
//然后收缩指针 看看 之间还有没有 符合的
l++;
r--;
//在找到相等的情况下,有数字重复就跳过
while(l<r&&nums[r]==nums[r+1]){ r--; }
while(l<r&&nums[l]==nums[l-1]){ l++; }
}
}
}
return ans;
}
};
难度中等820
给定一个包括 n 个整数的数组 nums
和 一个目标值 target
。找出 nums
中的三个整数,使得它们的和与 target
最接近。返回这三个数的和。假定每组输入只存在唯一答案。
示例:
输入:nums = [-1,2,1,-4], target = 1
输出:2
解释:与 target 最接近的和是 2 (-1 + 2 + 1 = 2) 。
提示:
3 <= nums.length <= 10^3
-10^3 <= nums[i] <= 10^3
-10^4 <= target <= 10^4
题解
class Solution {
public:
int threeSumClosest(vector<int>& nums, int target) {
int n=nums.size();
sort(nums.begin(),nums.end());
int l,r,sum,ans=nums[0]+nums[1]+nums[2];
for(int i=0;i<nums.size()-2;++i){
if(i>0 &&nums[i-1] == nums[i]) continue;
l = i+1;
r = n-1;
while(l<r){
sum=nums[i]+nums[l]+nums[r] ;
if(sum == target) return target;
if(abs(sum-target)<abs(ans-target)) ans=sum;
if(sum>target)r--;
else l++;
}
}
return ans;
}
};
难度中等
给定一个二维矩阵,计算其子矩形范围内元素的总和,该子矩阵的左上角为 (row1, col1)
,右下角为 (row2, col2)
。
上图子矩阵左上角 (row1, col1) = (2, 1) ,右下角(row2, col2) = **(4, 3),**该子矩形内元素的总和为 8。
示例:
给定 matrix = [
[3, 0, 1, 4, 2],
[5, 6, 3, 2, 1],
[1, 2, 0, 1, 5],
[4, 1, 0, 1, 7],
[1, 0, 3, 0, 5]
]
sumRegion(2, 1, 4, 3) -> 8
sumRegion(1, 1, 2, 2) -> 11
sumRegion(1, 2, 2, 4) -> 12
提示:
sumRegion
方法*。*row1 ≤ row2
且 col1 ≤ col2
。题解
using namespace std;
#include <vector>
class NumMatrix {
private:
vector<vector<int> > sums;
public:
NumMatrix(vector<vector<int> >& matrix) {
int n = matrix.size();
int m = matrix[0].size();
if (n == 0 || m == 0) {
return;
}
sums.resize(n + 1, vector<int>(m + 1, 0));
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
sums[i][j] = matrix[i - 1][j- 1] + sums[i - 1][j] + sums[i][j - 1] - sums[i - 1][j - 1];
}
}
return;
}
int sumRegion(int row1, int col1, int row2, int col2) {
return sums[row2 + 1][col2 + 1] - sums[row2 + 1][col1] - sums[row1][col2 + 1] + sums[row1][col1];
}
};
/**
* Your NumMatrix object will be instantiated and called as such:
* NumMatrix* obj = new NumMatrix(matrix);
* int param_1 = obj->sumRegion(row1,col1,row2,col2);
*/
难度中等250
如果一个数列至少有三个元素,并且任意两个相邻元素之差相同,则称该数列为等差数列。
例如,以下数列为等差数列:
1, 3, 5, 7, 9
7, 7, 7, 7
3, -1, -5, -9
以下数列不是等差数列。
1, 1, 2, 5, 7
数组 A 包含 N 个数,且索引从0开始。数组 A 的一个子数组划分为数组 (P, Q),P 与 Q 是整数且满足 0<=P<Q<N 。
如果满足以下条件,则称子数组(P, Q)为等差数组:
元素 A[P], A[p + 1], …, A[Q - 1], A[Q] 是等差的。并且 P + 1 < Q 。
函数要返回数组 A 中所有为等差数组的子数组个数。
示例:
A = [1, 2, 3, 4]
返回: 3, A 中有三个子等差数组: [1, 2, 3], [2, 3, 4] 以及自身 [1, 2, 3, 4]。
题解
//dp
class Solution {
public:
int numberOfArithmeticSlices(vector<int>& nums) {
int n=nums.size();
if(n<3) return 0;
int sum=0;
vector<int> dp(n,0);
for(int i=2;i<n;++i){
if(nums[i]-nums[i-1]==nums[i-1]-nums[i-2]) {
dp[i]=dp[i-1]+1;
sum+=dp[i]; //前缀和
}
}
return sum;
}
};
//优化dp
class Solution {
public:
int numberOfArithmeticSlices(vector<int>& nums) {
int n=nums.size();
if(n<3) return 0;
int sum=0;
int pre=0;
for(int i=2;i<n;++i){
if(nums[i]-nums[i-1]==nums[i-1]-nums[i-2]) {
pre=pre+1;
sum+=pre;
}
else pre=0;
}
return sum;
}
};