◉ 一、数组
912. 排序数组
给你一个整数数组 nums,请你将该数组升序排列。
示例 1:
输入:nums = [5,2,3,1]
输出:[1,2,3,5]
示例 2:
输入:nums = [5,1,1,2,0,0]
输出:[0,0,1,1,2,5]
提示:
1 <= nums.length <= 5 * 104
-5 * 104 <= nums[i] <= 5 * 104
题解
func Swap(x *int, y *int){
temp := *x
*x = *y
*y = temp
}
func Partition(nums *[]int, i int,j int) int{
idx := rand.Int()%(j-i+1)+i
Swap(&(*nums)[i],&(*nums)[idx])
x := (*nums)[i]
for i<j{
for i<j && (*nums)[j] >= x{
j--
}
(*nums)[i] = (*nums)[j]
for i<j && (*nums)[i]<=x {
i++
}
(*nums)[j] = (*nums)[i]
}
(*nums)[i] = x
return i
}
func quickSort(nums *[]int, s int, e int){
var m int
if (s<e){
m = Partition(nums,s,e)
quickSort(nums,s,m-1)
quickSort(nums,m+1,e)
}
}
func sortArray(nums []int) []int {
if len(nums) <=1 {
return nums
}
rand.New(rand.NewSource(time.Now().UnixNano()))
i,j := 0,len(nums)-1
quickSort(&nums,i,j)
return nums
}
1184. 公交站间的距离
难度:简单
环形公交路线上有 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;
}
};
1539. 第 k 个缺失的正整数
难度:简单
给你一个 严格升序排列 的正整数数组 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]
题解
方法一:
相当于找空座位
- 正常排列时,缺失的正整数一定 >= k
- 数组中每出现一个 <= k 的数字, 意味着少了一个缺失的数字, 此时k+1,向后挪一个位置
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];
}
41. 缺失的第一个正数
难度: 困难
给你一个未排序的整数数组 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;
}
};
剑指 Offer 03. 数组中重复的数字
难度: 简单
找出数组中重复的数字。
在一个长度为 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;
}
136. 只出现一次的数字
难度: 简单
给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。
说明:
你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?
示例 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 ;
}
};
283. 移动零
难度: 简单
给定一个数组 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;
}
88. 合并两个有序数组
难度: 简单
给你两个有序整数数组 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];
}
}
}
};
54. 螺旋矩阵
难度:中等
给你一个 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;
}
48. 旋转图像
难度:中等
给定一个 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;
}
}
}
};
349. 两个数组的交集
难度:简单
给定两个数组,编写一个函数来计算它们的交集。
示例 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;
}
};
189. 旋转数组
难度中等1002
给定一个数组,将数组中的元素向右移动 k
个位置,其中 k
是非负数。
进阶:
- 尽可能想出更多的解决方案,至少有三种不同的方法可以解决这个问题。
- 你可以使用空间复杂度为 O(1) 的 原地 算法解决这个问题吗?
示例 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());
}
};
525. 连续数组
难度中等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;
}
};
14. 最长公共前缀
难度简单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);
}
};
657. 机器人能否返回原点
难度简单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;
}
};
15. 三数之和
难度中等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;
}
};
16. 最接近的三数之和
难度中等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;
}
};
304. 二维区域和检索 - 矩阵不可变
难度中等
给定一个二维矩阵,计算其子矩形范围内元素的总和,该子矩阵的左上角为 (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);
*/
413. 等差数列划分
难度中等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;
}
};
31. 下一个排列
难度: 中等
实现获取 下一个排列 的函数,算法需要将给定数字序列重新排列成字典序中下一个更大的排列。
如果不存在下一个更大的排列,则将数字重新排列成最小的排列(即升序排列)。
必须** 原地 **修改,只允许使用额外常数空间。
示例 1:
输入:nums = [1,2,3]
输出:[1,3,2]
示例 2:
输入:nums = [3,2,1]
输出:[1,2,3]
示例 3:
输入:nums = [1,1,5]
输出:[1,5,1]
示例 4:
输入:nums = [1]
输出:[1]
提示:
1 <= nums.length <= 100
0 <= nums[i] <= 100
题解
逆向遍历找不符合 nums[i+1]<=nums[i] 的第一个不符合的index,然后逆序遍历找到不符合 nums[i]>=nums[j] 的index,交换 nums[i]和nums[j] ,反转 [begin+i+1,end) 的元素。
class Solution {
public:
void nextPermutation(vector<int>& nums) {
int i = nums.size() - 2;
while (i >= 0 && nums[i] >= nums[i + 1]) {
i--;
}
if (i >= 0) {
int j = nums.size() - 1;
while (j >= 0 && nums[i] >= nums[j]) {
j--;
}
swap(nums[i], nums[j]);
}
reverse(nums.begin() + i + 1, nums.end());
}
};
498. 对角线遍历
难度中等219
给定一个含有 M x N 个元素的矩阵(M 行,N 列),请以对角线遍历的顺序返回这个矩阵中的所有元素,对角线遍历如下图所示。
示例:
输入:
[
[ 1, 2, 3 ],
[ 4, 5, 6 ],
[ 7, 8, 9 ]
]
输出: [1,2,4,7,5,3,6,8,9]
解释:
说明:
- 给定矩阵中的元素总数不会超过 100000 。
题解
fx=1,代表方向为斜上↗;
fx=-1,代表方向为斜下↙;
class Solution {
public:
vector<int> findDiagonalOrder(vector<vector<int>>& mat) {
int m = mat.size();
if(!m)return {};
int n = mat[0].size();
vector<int> ans(m*n,0);
int cur = 0,i=0,j=0;
int fx=1;
for(;cur<m*n;++cur){
ans[cur]=mat[i][j];
if(j==n-1&&fx==1){ //遇到右边,则换向为斜下和移动起始点(向下)
fx=-1;
i=i+1;
continue;
}
if(i==m-1&&fx==-1){ //遇到下边,则换向为斜上和移动起始点(向右)
fx=1;
j=j+1;
continue;
}
if(i==0&&fx==1){ //遇到上边,则换向为斜下和移动起始点(向右)
fx=-1;
j = j+1;
continue;
}
if(j==0&&fx ==-1){ //遇到左边,则换向为斜上和移动起始点(向下)
fx=1;
i=i+1;
continue;
}
i=i-fx; //往斜上走,则分解为x方向向上,y方向向右
j=j+fx;
}
return ans;
}
};
443. 压缩字符串
难度中等258
给你一个字符数组 chars
,请使用下述算法压缩:
从一个空字符串 s
开始。对于 chars
中的每组 连续重复字符 :
- 如果这一组长度为
1
,则将字符追加到s
中。 - 否则,需要向
s
追加字符,后跟这一组的长度。
压缩后得到的字符串 s
不应该直接返回 ,需要转储到字符数组 chars
中。需要注意的是,如果组长度为 10
或 10
以上,则在 chars
数组中会被拆分为多个字符。
请在 修改完输入数组后 ,返回该数组的新长度。
你必须设计并实现一个只使用常量额外空间的算法来解决此问题。
示例 1:
输入:chars = ["a","a","b","b","c","c","c"]
输出:返回 6 ,输入数组的前 6 个字符应该是:["a","2","b","2","c","3"]
解释:
"aa" 被 "a2" 替代。"bb" 被 "b2" 替代。"ccc" 被 "c3" 替代。
示例 2:
输入:chars = ["a"]
输出:返回 1 ,输入数组的前 1 个字符应该是:["a"]
解释:
没有任何字符串被替代。
示例 3:
输入:chars = ["a","b","b","b","b","b","b","b","b","b","b","b","b"]
输出:返回 4 ,输入数组的前 4 个字符应该是:["a","b","1","2"]。
解释:
由于字符 "a" 不重复,所以不会被压缩。"bbbbbbbbbbbb" 被 “b12” 替代。
注意每个数字在数组中都有它自己的位置。
提示:
1 <= chars.length <= 2000
chars[i]
可以是小写英文字母、大写英文字母、数字或符号
题解
class Solution {
public:
int compress(vector<char>& chars) {
int len = 0;
for (int i = 0, cnt = 1; i < chars.size(); i++, cnt++) {
if (i + 1 == chars.size() || chars[i] != chars[i + 1]) {
chars[len++] = chars[i];
if (cnt > 1) {
for (char ch : to_string(cnt)) {
chars[len++] = ch;
}
}
cnt = 0;
}
}
return len;
}
};
◉ 二、摩尔投票法
1. 多数元素
给定一个大小为 n 的数组,找到其中的多数元素。多数元素是指在数组中出现次数 大于 ⌊ n/2 ⌋
的元素。
你可以假设数组是非空的,并且给定的数组总是存在多数元素。
示例 1:
输入:[3,2,3]
输出:3
示例 2:
输入:[2,2,1,1,1,2,2]
输出:2
题解
class Solution {
public:
int majorityElement(vector<int>& nums) {
int count = 0, res = 0;
for (int &item : nums) {
if (count == 0) res = item, count++;//统计为0,换主元素
else if (res != item) count--;//不相同则斗争,相抵消
else if (res == item) count++;//相同,为一伙的
}
return res;
}
};
2. 求众数 II
难度中等362收藏分享切换为英文接收动态反馈
给定一个大小为 n 的整数数组,找出其中所有出现超过 ⌊ n/3 ⌋
次的元素。
**进阶:**尝试设计时间复杂度为 O(n)、空间复杂度为 O(1)的算法解决此问题。
示例 1:
输入:[3,2,3]
输出:[3]
示例 2:
输入:nums = [1]
输出:[1]
示例 3:
输入:[1,1,1,3,3,2,2,2]
输出:[1,2]
题解
//摩尔投票法
class Solution {
public:
vector<int> majorityElement(vector<int>& nums) {
int candicate1 = nums[0];
int candicate2 = nums[0];
int count1 = 0;
int count2 = 0;
for(int& num :nums){
if(candicate1==num){
count1++;
continue;
}
if(candicate2==num){
count2++;
continue;
}
if(count1==0){
candicate1=num;
count1++;
continue;
}
if(count2==0){
candicate2=num;
count2++;
continue;
}
count1--;
count2--;
}
count1=0;
count2=0;
//可能有一个,可能有两个,可能一个,可能没有
for(int& num: nums){
if(num==candicate1){
count1++;
}else if(num==candicate2){
count2++;
}
}
vector<int> res;
if(count1>nums.size()/3){
res.push_back(candicate1);
}
if(count2>nums.size()/3){
res.push_back(candicate2);
}
return res;
}
};
◉ 三、哈希表
220. 存在重复元素 III
给你一个整数数组 nums
和两个整数 k
和 t
。请你判断是否存在 两个不同下标 i
和 j
,使得 abs(nums[i] - nums[j]) <= t
,同时又满足 abs(i - j) <= k
。
如果存在则返回 true
,不存在返回 false
。
示例 1:
输入:nums = [1,2,3,1], k = 3, t = 0
输出:true
示例 2:
输入:nums = [1,0,1,1], k = 1, t = 2
输出:true
示例 3:
输入:nums = [1,5,9,1,5,9], k = 2, t = 3
输出:false
题解
/*在默认的情况下cin绑定的是cout,每次执行 << 操作符的时候都要调用flush,这样会增加IO负担。可以通过tie(0)(0表示NULL)来解除cin与cout的绑定,进一步加快执行效率。*/
static int x=[](){
ios::sync_with_stdio(false);
cin.tie(NULL);
return 0;
}();
class Solution {
public:
long getID(long x, long t){
//如果x元素大于等于零,直接分桶
if(x>=0){
return x / ( t + 1 );
}else{
//如果x元素小于零,偏移后再分桶
return ( x + 1 )/( t + 1 ) - 1 ;
}
return 0;
}
bool containsNearbyAlmostDuplicate(vector<int>& nums, int k, int t) {
int n = nums.size();
//我们用unordered_map来实现桶,其底层实现是一个哈希表.
unordered_map<int,int> m;
for(int i = 0 ; i < n; i++ ){
//当前元素
long x = nums[i];
//给当前元素生成id,这里我们同一个id的桶内元素满足abs(nums[i] - nums[j]) <= t
int id = getID(x,t);
//前面的i-(k+1)是超出了范围的桶,我们把它提前删除,以免影响判断
if( i-(k+1) >= 0 ){
//把下标不满足我们判断范围的桶删除了
m.erase(getID(nums[i-(k+1)],t));
}
//看看当前元素属于的桶中有没有元素
if(m.find(id)!=m.end()){
return true;
}
//看看前面相邻桶有没有符合条件的
if(m.find(id - 1) != m.end() && abs(m[id-1]-x) <= t){
return true;
}
//看看后面相邻桶有没有符合条件的
if(m.find(id + 1) != m.end() && abs(m[id+1]-x) <= t){
return true;
}
//分桶,把这个元素放入其属于的桶
m[id] = x;
}
return false;
}
};
*128. 最长连续序列
难度中等839收藏分享切换为英文接收动态反馈
给定一个未排序的整数数组 nums
,找出数字连续的最长序列(不要求序列元素在原数组中连续)的长度。
请你设计并实现时间复杂度为 O(n)
的算法解决此问题。
示例 1:
输入:nums = [100,4,200,1,3,2]
输出:4
解释:最长数字连续序列是 [1, 2, 3, 4]。它的长度为 4。
示例 2:
输入:nums = [0,3,7,2,5,8,4,6,0,1]
输出:9
提示:
0 <= nums.length <= 105
-109 <= nums[i] <= 109
题解
class Solution {
public:
int longestConsecutive(vector<int>& nums) {
if(nums.size()<2)return nums.size();
int ans=0;
int temp=0;
unordered_set<int>m;
for(const int&e:nums) m.insert(e);
for(int e:nums){
if(!m.count(e-1)){
temp=1;
while(m.count(e+1)){
e++;
temp++;
}
}
ans = max(ans,temp);
}
return ans;
}
};
3. 无重复字符的最长子串
给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。
示例 1:
输入: s = "abcabcbb"
输出: 3
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。
示例 2:
输入: s = "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。
示例 3:
输入: s = "pwwkew"
输出: 3
解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。
请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。
示例 4:
输入: s = ""
输出: 0
题解
int lengthOfLongestSubstring(const string& s) {
if(s.size()==0)return 0;
if(s.size()==1) return 1;
bitset<128>map;
int ans=1;
map[s[0]]=1;
int i=0,j=0;
while(j<s.size()){ //map只记录滑动窗口的元素,移出滑动窗口后,从删除对应的元素
ans=max(ans,j-i+1);
++j;
while(0!=map[s[j]]){//重复了
map[s[i]]=0;//向前移动i
++i;
}
map[s[j]]=1;
}
return ans;
}
930. 和相同的二元子数组
难度: 中等
给你一个二元数组 nums
,和一个整数 goal
,请你统计并返回有多少个和为 goal
的 非空 子数组。
子数组 是数组的一段连续部分。
示例 1:
输入:nums = [1,0,1,0,1], goal = 2
输出:4
解释:
如下面黑体所示,有 4 个满足题目要求的子数组:
[1,0,1,0,1]
[1,0,1,0,1]
[1,0,1,0,1]
[1,0,1,0,1]
示例 2:
输入:nums = [0,0,0,0,0], goal = 0
输出:15
提示:
1 <= nums.length <= 3 * 104
nums[i]
不是0
就是1
0 <= goal <= nums.length
题解
//前缀和
class Solution {
public:
int numSubarraysWithSum(vector<int>& nums, int goal) {
unordered_map<int,int> m; //保存前缀和
m[0]=1;
int sum=0;
long long ans=0;
for(int i=0;i<nums.size();++i){
sum+=nums[i];
ans+=m[sum-goal];
m[sum]++;
}
return ans;
}
};
13. 罗马数字转整数
难度:简单
罗马数字包含以下七种字符: I
, V
, X
, L
,C
,D
和 M
。
字符 数值
I 1
V 5
X 10
L 50
C 100
D 500
M 1000
例如, 罗马数字 2 写做 II
,即为两个并列的 1。12 写做 XII
,即为 X
+ II
。 27 写做 XXVII
, 即为 XX
+ V
+ II
。
通常情况下,罗马数字中小的数字在大的数字的右边。但也存在特例,例如 4 不写做 IIII
,而是 IV
。数字 1 在数字 5 的左边,所表示的数等于大数 5 减小数 1 得到的数值 4 。同样地,数字 9 表示为 IX
。这个特殊的规则只适用于以下六种情况:
I
可以放在V
(5) 和X
(10) 的左边,来表示 4 和 9。X
可以放在L
(50) 和C
(100) 的左边,来表示 40 和 90。C
可以放在D
(500) 和M
(1000) 的左边,来表示 400 和 900。
给定一个罗马数字,将其转换成整数。输入确保在 1 到 3999 的范围内。
示例 1:
输入: "III"
输出: 3
示例 2:
输入: "IV"
输出: 4
示例 3:
输入: "IX"
输出: 9
示例 4:
输入: "LVIII"
输出: 58
解释: L = 50, V= 5, III = 3.
示例 5:
输入: "MCMXCIV"
输出: 1994
解释: M = 1000, CM = 900, XC = 90, IV = 4.
提示:
1 <= s.length <= 15
s
仅含字符('I', 'V', 'X', 'L', 'C', 'D', 'M')
- 题目数据保证
s
是一个有效的罗马数字,且表示整数在范围[1, 3999]
内 - 题目所给测试用例皆符合罗马数字书写规则,不会出现跨位等情况。
- IL 和 IM 这样的例子并不符合题目要求,49 应该写作 XLIX,999 应该写作 CMXCIX 。
- 关于罗马数字的详尽书写规则,可以参考 罗马数字 - Mathematics 。
题解
class Solution {
public:
int romanToInt(string s) {
int i = 0, n = 0;
int len = s.size();
int hash[26] = {0};
hash['I'-'A'] = 1;
hash['V'-'A'] = 5;
hash['X'-'A'] = 10;
hash['L'-'A'] = 50;
hash['C'-'A'] = 100;
hash['D'-'A'] = 500;
hash['M'-'A'] = 1000;
while (i < len)
{
if (i + 1 < len && hash[s[i]-'A'] < hash[s[i + 1]-'A'])
{
n = n + hash[s[i + 1]-'A'] - hash[s[i]-'A'];
i = i + 2;
}
else
{
n = n + hash[s[i]-'A'];
i++;
}
}
return n;
}
};
1248. 统计「优美子数组」
难度中等175收藏分享切换为英文接收动态反馈
给你一个整数数组 nums
和一个整数 k
。
如果某个 连续 子数组中恰好有 k
个奇数数字,我们就认为这个子数组是「优美子数组」。
请返回这个数组中「优美子数组」的数目。
示例 1:
输入:nums = [1,1,2,1,1], k = 3
输出:2
解释:包含 3 个奇数的子数组是 [1,1,2,1] 和 [1,2,1,1] 。
示例 2:
输入:nums = [2,4,6], k = 1
输出:0
解释:数列中不包含任何奇数,所以不存在优美子数组。
示例 3:
输入:nums = [2,2,2,1,2,2,1,2,2,2], k = 2
输出:16
提示:
1 <= nums.length <= 50000
1 <= nums[i] <= 10^5
1 <= k <= nums.length
题解
前缀和
static int x=[](){
ios::sync_with_stdio(0);
cin.tie(0);
return 0;
}();
class Solution {
public:
int numberOfSubarrays(vector<int>& nums, int k) {
unordered_map<int,int>m;
m[0]=1; //key!!!
int ans=0;
int sum=0;
for(int i=0;i<nums.size();++i){
sum+=(nums[i]&1)?1:0;
if(m.count(sum-k)) ans+=m[sum-k];
m[sum]++;
}
return ans;
}
};
724. 寻找数组的中心下标
难度:简单
给你一个整数数组 nums
,请计算数组的 中心下标 。
数组 中心下标 是数组的一个下标,其左侧所有元素相加的和等于右侧所有元素相加的和。
如果中心下标位于数组最左端,那么左侧数之和视为 0
,因为在下标的左侧不存在元素。这一点对于中心下标位于数组最右端同样适用。
如果数组有多个中心下标,应该返回 最靠近左边 的那一个。如果数组不存在中心下标,返回 -1
。
示例 1:
输入:nums = [1, 7, 3, 6, 5, 6]
输出:3
解释:
中心下标是 3 。
左侧数之和 sum = nums[0] + nums[1] + nums[2] = 1 + 7 + 3 = 11 ,
右侧数之和 sum = nums[4] + nums[5] = 5 + 6 = 11 ,二者相等。
示例 2:
输入:nums = [1, 2, 3]
输出:-1
解释:
数组中不存在满足此条件的中心下标。
示例 3:
输入:nums = [2, 1, -1]
输出:0
解释:
中心下标是 0 。
左侧数之和 sum = 0 ,(下标 0 左侧不存在元素),
右侧数之和 sum = nums[1] + nums[2] = 1 + -1 = 0 。
提示:
1 <= nums.length <= 104
-1000 <= nums[i] <= 1000
题解
//前缀和
class Solution {
public:
int pivotIndex(vector<int>& nums) {
int n = nums.size();
vector<int>s1(n+2,0) ; //前缀和s1
vector<int>s2(n+2,0) ; //前缀和s2
for (int i = 1; i <= n; i++) s1[i] = s1[i - 1] + nums[i - 1];
for (int i = n; i >= 1; i--) s2[i] = s2[i + 1] + nums[i - 1];
for (int i = 1; i <= n; i++) {
if (s1[i] == s2[i]) return i - 1;
}
return -1;
}
};
//优化前缀和
class Solution {
public:
int pivotIndex(vector<int>& nums) {
int n = nums.size();
int total = 0, sum = 0;
for (int i = 0; i < n; i++) total += nums[i];
for (int i = 0; i < n; i++) {
if (sum == total - sum - nums[i]) return i;
sum += nums[i];
}
return -1;
}
};
1109. 航班预订统计
难度中等153收藏分享切换为英文接收动态反馈
这里有 n
个航班,它们分别从 1
到 n
进行编号。
有一份航班预订表 bookings
,表中第 i
条预订记录 bookings[i] = [firsti, lasti, seatsi]
意味着在从 firsti
到 lasti
(包含 firsti
和 lasti
)的 每个航班 上预订了 seatsi
个座位。
请你返回一个长度为 n
的数组 answer
,其中 answer[i]
是航班 i
上预订的座位总数。
示例 1:
输入:bookings = [[1,2,10],[2,3,20],[2,5,25]], n = 5
输出:[10,55,45,25,25]
解释:
航班编号 1 2 3 4 5
预订记录 1 : 10 10
预订记录 2 : 20 20
预订记录 3 : 25 25 25 25
总座位数: 10 55 45 25 25
因此,answer = [10,55,45,25,25]
示例 2:
输入:bookings = [[1,2,10],[2,2,15]], n = 2
输出:[10,25]
解释:
航班编号 1 2
预订记录 1 : 10 10
预订记录 2 : 15
总座位数: 10 25
因此,answer = [10,25]
提示:
1 <= n <= 2 * 104
1 <= bookings.length <= 2 * 104
bookings[i].length == 3
1 <= firsti <= lasti <= n
1 <= seatsi <= 104
题解
class Solution {
public:
vector<int> corpFlightBookings(vector<vector<int>>& bookings, int n) {
vector<int> presum(n,0);
for(auto &x:bookings){ //差分法
presum[x[0]-1]+=x[2]; //上飞机,注意编号是从1到n,所以要-1;
if(x[1]-1<n-1){
presum[x[1]+1-1]-=x[2]; //下飞机,但是到终点站下的不用减
}
}
for(int i =1;i<n;i++){
presum[i]+=presum[i-1]; //前缀和得到各站的人数
}
return presum;
}
};
525. 连续数组
难度中等438
给定一个二进制数组 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
题解
前缀和三部曲:
- hash保存的下标还是数值。(下标对应子数组长度,数值对应和为k的个数)
- hash[0]的含义。统计个数时,hash[0]代表sumk时,个数记为1。计算数组长度时,hash[0]代表sumk时,索引的位置。
class Solution {
public:
int findMaxLength(vector<int>& nums) {
int res=0,sum=0;
unordered_map<int,int>umap;
umap[0]=-1; //考虑sum==k的情况
for(int i=0;i<nums.size();++i){
sum+= (nums[i]==0?-1:1);
if(umap.count(sum-0)){ //target=0
res=max(res,i-umap[sum]);
}
else{
umap[sum]=i;
}
}
return res;
}
};
325.和等于 k 的最长子数组长度
题目描述:
给定一个数组 nums 和一个目标值 k,找到和等于 k 的最长子数组长度。如果不存在任意一个符合要求的子数组,则返回 0。
注意:
nums 数组的总和是一定在 32 位有符号整数范围之内的。
示例 1:
输入: nums = [1, -1, 5, -2, 3], k = 3
输出: 4
解释: 子数组 [1, -1, 5, -2] 和等于 3,且长度最长。
示例 2:
输入: nums = [-2, -1, 2, 1], k = 1
输出: 2
解释: 子数组 [-1, 2] 和等于 1,且长度最长。
题解
//
class Solution {
public:
int maxSubArrayLen(vector<int>& nums, int k) {
//利用前缀和数组 快速计算子数组的和
//而又因为求的是最长子数组等于k,所以我们在哈希表中保存的是前缀和为x第一次出现的下标
//然后我们求以每个元素为结尾的,最长 和等于k的子数组长度
//值为x的前缀和最早出现的下标y hash【x】=y
unordered_map<int,int> hash;
// 这个初始化很重要,为了考虑到 0~i等于k的情况
hash[0]=-1;
int sum=0;
int res=0;
for(int i=0;i<nums.size();++i){
sum += nums[i];
if(hash.count(sum-k)) res= max(res,i-hash[sum-k]);
if(!hash.count(sum)) hash[sum]=i; // 因为要的是第一次出现的值
}
return res;
}
};
1. 两数之和
难度:简单
给定一个整数数组 nums
和一个整数目标值 target
,请你在该数组中找出 和为目标值 target
的那 两个 整数,并返回它们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。
你可以按任意顺序返回答案。
示例 1:
输入:nums = [2,7,11,15], target = 9
输出:[0,1]
解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。
示例 2:
输入:nums = [3,2,4], target = 6
输出:[1,2]
示例 3:
输入:nums = [3,3], target = 6
输出:[0,1]
提示:
2 <= nums.length <= 104
-109 <= nums[i] <= 109
-109 <= target <= 109
- 只会存在一个有效答案
题解
class Solution {
public:
vector<int> twoSum(vector<int>& nums,const int& target) {
unordered_map<int,int> m;
unordered_map<int,int> ::iterator it;
for(int i=0;i<nums.size();++i){
it = m.find(target-nums[i]);
if(it!=m.end()){return vector<int>({i,it->second}); }
m[nums[i]]=i;
}
return vector<int>();
}
};
12. 整数转罗马数字
难度中等674
罗马数字包含以下七种字符: I
, V
, X
, L
,C
,D
和 M
。
字符 数值
I 1
V 5
X 10
L 50
C 100
D 500
M 1000
例如, 罗马数字 2 写做 II
,即为两个并列的 1。12 写做 XII
,即为 X
+ II
。 27 写做 XXVII
, 即为 XX
+ V
+ II
。
通常情况下,罗马数字中小的数字在大的数字的右边。但也存在特例,例如 4 不写做 IIII
,而是 IV
。数字 1 在数字 5 的左边,所表示的数等于大数 5 减小数 1 得到的数值 4 。同样地,数字 9 表示为 IX
。这个特殊的规则只适用于以下六种情况:
I
可以放在V
(5) 和X
(10) 的左边,来表示 4 和 9。X
可以放在L
(50) 和C
(100) 的左边,来表示 40 和 90。C
可以放在D
(500) 和M
(1000) 的左边,来表示 400 和 900。
给你一个整数,将其转为罗马数字。
示例 1:
输入: num = 3
输出: "III"
示例 2:
输入: num = 4
输出: "IV"
示例 3:
输入: num = 9
输出: "IX"
示例 4:
输入: num = 58
输出: "LVIII"
解释: L = 50, V = 5, III = 3.
示例 5:
输入: num = 1994
输出: "MCMXCIV"
解释: M = 1000, CM = 900, XC = 90, IV = 4.
提示:
1 <= num <= 3999
题解
class Solution {
public:
string intToRoman(int num) {
int values[]={1000,900,500,400,100,90,50,40,10,9,5,4,1};
string reps[]={"M","CM","D","CD","C","XC","L","XL","X","IX","V","IV","I"};
string res;
for(int i=0; i<13; i++){
while(num>=values[i]){
num -= values[i];
res += reps[i];
}
}
return res;
}
};
◉ 四、链表
链表定义
struct ListNode {
int val;
ListNode *next;
ListNode(int x) : val(x), next(NULL) {}
};
剑指 Offer 24. 反转链表
定义一个函数,输入一个链表的头节点,反转该链表并输出反转后链表的头节点。
示例:
输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL
限制:
0 <= 节点个数 <= 5000
题解
//迭代法
class Solution {
public:
ListNode* reverseList(ListNode* head) {
if(!head||!head->next)return head;
ListNode * newh=nullptr;
ListNode * p=head;
while(head){
p= head->next;
head->next = newh;
newh = head;
head =p;
}
return newh;
}
};
//递归法
class Solution {
public:
ListNode* reverseList(ListNode* head) {
if (head == NULL || head->next == NULL) {
return head;
}
ListNode* ret = reverseList(head->next);
head->next->next = head;
head-&g