Leetcode Hot100
31. 下一个排列
实现获取下一个排列的函数,算法需要将给定数字序列重新排列成字典序中下一个更大的排列。
如果不存在下一个更大的排列,则将数字重新排列成最小的排列(即升序排列)。
必须原地修改,只允许使用额外常数空间。
以下是一些例子,输入位于左侧列,其相应输出位于右侧列。
1,2,3 → 1,3,2
3,2,1 → 1,2,3
1,1,5 → 1,5,1
思路:参考
class Solution {
public:
void nextPermutation(vector<int>& nums) {
int pos=nums.size()-2;
while(pos>=0 &&nums[pos]>=nums[pos+1]){
pos--;
}
reverse(nums.begin()+pos+1,nums.end());
if(pos>=0){
int start=pos;
for(;start<=nums.size()-1;start++){
if(nums[start]>nums[pos]){
swap(nums[start],nums[pos]);
break;
}
}
}
}
};
24. 两两交换链表中的节点
给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。
你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。
思路:参考
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* swapPairs(ListNode* head) {
ListNode *dummy=new ListNode(0);
//针对只有[1]的情况做的下面的处理
dummy->next=head;
ListNode *first;
ListNode *second;
ListNode *prevNode=dummy;
while(head!=NULL && head->next!=NULL){
first=head;
second=head->next;
prevNode->next=second;
first->next=second->next;
second->next=first;
prevNode=first;
head=first->next;
}
return dummy->next;
}
};
Z字形变换
将一个给定字符串根据给定的行数,以从上往下、从左到右进行 Z 字形排列。
比如输入字符串为 “LEETCODEISHIRING” 行数为 3 时,排列如下:
L C I R
E T O E S I I G
E D H N
之后,你的输出需要从左往右逐行读取,产生出一个新的字符串,比如:“LCIRETOESIIGEDHN”
思路:参考
class Solution {
public:
string convert(string s, int numRows) {
if(numRows<2)return s;
string res;
vector<string>temp(numRows,"");
int i=0,flag=-1;
for(auto x:s){
temp[i]+=x;
if(i==numRows-1||i==0)flag=-flag;
i+=flag;
}
for(int i=0;i<temp.size();i++){
res+=temp[i];
}
return res;
}
};
1. 两数之和
给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素不能使用两遍。
思路:参考
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
unordered_map <int,int> mymap;
for(int i=0;i<nums.size();i++){
int component =target-nums[i];
if(mymap.find(component)!=mymap.end()){
return {mymap[component],i};
}
mymap[nums[i]]=i;
}
return {};
}
};
12. 整数转罗马数字
罗马数字包含以下七种字符: 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 的范围内。
思路:参考
class Solution {
public:
string intToRoman(int num) {
string res="";
vector<int>values={1000,900,500,400,100,90,50,40,10,9,5,4,1};
vector<string> reps={"M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I"};
for(int i=0;i<values.size();i++){
while(num>=values[i]){
num-=values[i];
res+=reps[i];
}
}
return res;
}
};
15. 三数之和
给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有满足条件且不重复的三元组。
注意:答案中不可以包含重复的三元组。
思路:参考
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
vector<vector<int>>res;
sort(nums.begin(),nums.end());
int n=nums.size();
for(int first=0;first<n;first++){
if(first>0&& nums[first]==nums[first-1])continue;
int third=n-1;
for(int second=first+1;second<n;second++){
if(second>first+1 && nums[second]==nums[second-1])continue;
while(second<third && nums[second]+nums[third]+nums[first]>0){
third--;
}
if(second==third)break;
if(nums[first]+nums[third]+nums[second]==0){
res.push_back({nums[first],nums[second],nums[third]});
}
}
}
return res;
}
};
18. 四数之和
给定一个包含 n 个整数的数组 nums 和一个目标值 target,判断 nums 中是否存在四个元素 a,b,c 和 d ,使得 a + b + c + d 的值与 target 相等?找出所有满足条件且不重复的四元组。
思路:参考3数之和
class Solution {
public:
vector<vector<int>> fourSum(vector<int>& nums, int target) {
int n=nums.size();
vector<vector<int>>res;
sort(nums.begin(),nums.end());
for(int first=0;first<n;first++){
if(first>0&&nums[first]==nums[first-1])continue;
for(int second=first+1;second<n;second++){
if(second>first+1 && nums[second]==nums[second-1])continue;
int forth=n-1;
for(int third=second+1;third<n;third++){
if(third>second+1 &&nums[third]==nums[third-1])continue;
while(third<forth && nums[first]+nums[second]+nums[third]+nums[forth]>target){
forth--;
}
if(third==forth)break;
if(nums[first]+nums[second]+nums[third]+nums[forth]==target){
res.push_back({nums[first],nums[second],nums[third],nums[forth]});
}
}
}
}
return res;
}
};
39. 组合总和
给定一个无重复元素的数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。
candidates 中的数字可以无限制重复被选取。
说明:
所有数字(包括 target)都是正整数。
解集不能包含重复的组合。
思路:参考
class Solution {
public:
void DFS(int start ,int target){
if(target==0){
res.push_back(path);
return;
}
for(int i=start;i<candidates.size();i++){
if(target-candidates[i]>=0){
path.push_back(candidates[i]);
DFS(i,target-candidates[i]);
path.pop_back();
}
}
}
vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
sort(candidates.begin(),candidates.end());
this->candidates=candidates;
DFS(0,target);
return res;
}
private:
vector<vector<int>>res;
vector<int>candidates;
vector<int>path;
};
34. 在排序数组中查找元素的第一个和最后一个位置
给定一个按照升序排列的整数数组 nums,和一个目标值 target。找出给定目标值在数组中的开始位置和结束位置。
你的算法时间复杂度必须是 O(log n) 级别。
如果数组中不存在目标值,返回 [-1, -1]。
思路:二分法
class Solution {
public:
vector<int> searchRange(vector<int>& nums, int target) {
int left=0;
int right=nums.size()-1;
while(left<=right){
int mid=(left+right)/2;
if(nums[mid]==target){
left=mid;
right=mid;
while(left>=0 &&nums[left]==target)left--;
while(right<=nums.size()-1 && nums[right]==target)right++;
return {left+1,right-1};
}
else if(nums[mid]<target){
left=mid+1;
}
else{
right=mid-1;
}
}
return {-1,-1};
}
};
55. 跳跃游戏
给定一个非负整数数组,你最初位于数组的第一个位置。
数组中的每个元素代表你在该位置可以跳跃的最大长度。
判断你是否能够到达最后一个位置。
思路:参考
class Solution {
public:
bool canJump(vector<int>& nums) {
int n=nums.size();
int rightmost=0;
for(int i=0;i<n;i++){
if(i<=rightmost){
rightmost=max(rightmost,i+nums[i]);
if(rightmost>=n-1){
return true;
}
}
}
return false;
}
};
33. 搜索旋转排序数组
假设按照升序排序的数组在预先未知的某个点上进行了旋转。
( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] )。
搜索一个给定的目标值,如果数组中存在这个目标值,则返回它的索引,否则返回 -1 。
你可以假设数组中不存在重复的元素。
你的算法时间复杂度必须是 O(log n) 级别。
思路:二分法
class Solution {
public:
int search(vector<int>& nums, int target) {
int n=nums.size();
if(!n)return -1;
if(n==1)return nums[0]==target ? 0:-1;
int l=0;
int r=n-1;
while(l<=r){
int mid=(l+r)/2;
if (nums[mid]==target)return mid;
if(nums[l]<=nums[mid]){
if(nums[l]<=target && target<nums[mid] ){
r=mid-1;
}
else{
l=mid+1;
}
}
else{
if(nums[mid]<target && target<=nums[n-1] ){
l=mid+1;
}
else{
r=mid-1;
}
}
}
return -1;
}
};
56. 合并区间
给出一个区间的集合,请合并所有重叠的区间。
示例 1:
输入: [[1,3],[2,6],[8,10],[15,18]]
输出: [[1,6],[8,10],[15,18]]
解释: 区间 [1,3] 和 [2,6] 重叠, 将它们合并为 [1,6].
思路:参考
class Solution {
public:
vector<vector<int>> merge(vector<vector<int>>& intervals) {
if(intervals.size()==0)return {};
sort(intervals.begin(),intervals.end());
for(int i=0;i<intervals.size();i++){
int L=intervals[i][0],R=intervals[i][1];
if(res.size()==0||res.back()[1]<L){
res.push_back({L,R});
}
else{
res.back()[1]=max(res.back()[1],R);
}
}
return res;
}
private:
vector<vector<int>>res;
};
48. 旋转图像
给定一个 n × n 的二维矩阵表示一个图像。
将图像顺时针旋转 90 度。
说明:
你必须在原地旋转图像,这意味着你需要直接修改输入的二维矩阵。请不要使用另一个矩阵来旋转图像。
思路:参考
class Solution {
public:
void rotate(vector<vector<int>> & matrix) {
int n = matrix.size();
for(int i=0;i<n;i++){
for(int j=i;j<n;j++){
int tmp=matrix[i][j];
matrix[i][j]=matrix[j][i];
matrix[j][i]=tmp;
}
}
for(int i=0;i<n;i++){
for(int j=0;j<n/2;j++){
int tmp=matrix[i][j];
matrix[i][j]=matrix[i][n-1-j];
matrix[i][n-1-j]=tmp;
}
}
}
};
78. 子集
给定一组不含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。
说明:解集不能包含重复的子集。
思路:参考
class Solution {
public:
void backtrack(vector<int> & nums,int pos){
res.push_back(cur);
for(int i=pos;i<nums.size();i++){
cur.push_back(nums[i]);
backtrack(nums,i+1);
cur.pop_back();
}
}
vector<vector<int>> subsets(vector<int>& nums) {
backtrack(nums,0);
return res;
}
private:
vector<vector<int>>res;
vector<int>cur;
};
93. 复原IP地址
给定一个只包含数字的字符串,复原它并返回所有可能的 IP 地址格式。
有效的 IP 地址正好由四个整数(每个整数位于 0 到 255 之间组成),整数之间用 ‘.’ 分隔。
思路:参考
class Solution {
public:
bool isValid(const string ip){
int val=stoi(ip);
if(val>255)return false;
if(ip.size()>=2 &&ip[0]=='0')return false;
return true;
}
void backtrack(const string &s,int pos,vector<string> &path){
int maxLen=(4-path.size())*3;
if(s.size()-pos>maxLen)return;
if(path.size()==4 && pos==s.size()){
string ans="";
for(int i=0;i<4;i++){
ans+=path[i];
if(i!=3) ans+=".";
}
res.push_back(ans);
return;
}
for (int i=pos;i<s.size()&& i<=pos+2;i++){
string ip=s.substr(pos,i-pos+1);
if(!isValid(ip))continue;
path.push_back(ip);
backtrack(s,i+1,path);
path.pop_back();
}
}
vector<string> restoreIpAddresses(string s) {
vector<string>path;
backtrack(s,0,path);
return res;
}
private:
vector<string>res;
};
43. 字符串相乘
给定两个以字符串形式表示的非负整数 num1 和 num2,返回 num1 和 num2 的乘积,它们的乘积也表示为字符串形式。
思路:参考
class Solution {
public:
string multiply(string num1, string num2) {
int n1=num1.size();
int n2=num2.size();
string res(n1+n2,'0');
for(int i=n2-1;i>=0;i--){
for(int j=n1-1;j>=0;j--){
int temp=(res[i+j+1]-'0')+(num2[i]-'0')*(num1[j]-'0');
res[i+j+1]=temp%10+'0';
res[i+j]+=temp/10;
}
}
for(int i=0;i<n1+n2;i++){
if(res[i]!='0')
return res.substr(i);
}
return "0";
}
};
64. 最小路径和
给定一个包含非负整数的 m x n 网格,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。
说明:每次只能向下或者向右移动一步。
思路:动态规划
class Solution {
public:
int minPathSum(vector<vector<int>>& grid) {
int row =grid.size();
int colum=grid[0].size();
vector<vector<int>> dp(row,vector<int>(colum,0));
dp[0][0]=grid[0][0];
for(int i=1;i<row;i++){
dp[i][0]=dp[i-1][0]+grid[i][0];
}
for(int i=1;i<colum;i++){
dp[0][i]=dp[0][i-1]+grid[0][i];
}
for(int i=1;i<row;i++){
for (int j=1;j<colum;j++){
dp[i][j]=min(dp[i-1][j],dp[i][j-1])+grid[i][j];
}
}
return dp[row-1][colum-1];
}
};
114. 二叉树展开为链表
给定一个二叉树,原地将它展开为一个单链表。
思路:参考解法一
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
void flatten(TreeNode* root) {
while(root!=NULL){
if(root->left==NULL){
root=root->right;
}
else{
TreeNode *pre=root->left;
while(pre->right!=NULL){
pre=pre->right;
}
pre->right=root->right;
root->right=root->left;
root->left=NULL;
root=root->right;
}
}
}
};
49. 字母异位词分组
给定一个字符串数组,将字母异位词组合在一起。字母异位词指字母相同,但排列不同的字符串。
思路:参考
class Solution {
public:
vector<vector<string>> groupAnagrams(vector<string>& strs) {
vector<vector<string>>res;
unordered_map<string ,vector<string>> mymap;
for (auto s:strs){
string temp=s;
sort(temp.begin(),temp.end());
mymap[temp].push_back(s);
}
for(auto p=mymap.begin();p!=mymap.end();p++){
res.push_back(p->second);
}
return res;
}
};
22. 括号生成
数字 n 代表生成括号的对数,请你设计一个函数,用于能够生成所有可能的并且 有效的 括号组合。
思路:参考
class Solution {
public:
void backtrack(string path,int n,int left,int right){
if(left==n &&right==n){
res.push_back(path);
return;
}
if(left>n ||right>n|| right>left )return;
backtrack(path+'(',n,left+1,right);
backtrack(path+')',n,left,right+1);
}
vector<string> generateParenthesis(int n) {
string path="";
backtrack(path,n,0,0);
return res;
}
private:
vector<string>res;
};
200. 岛屿数量
给你一个由 ‘1’(陆地)和 ‘0’(水)组成的的二维网格,请你计算网格中岛屿的数量。
岛屿总是被水包围,并且每座岛屿只能由水平方向或竖直方向上相邻的陆地连接形成。
此外,你可以假设该网格的四条边均被水包围。
思路:参考
class Solution {
public:
void dfs(vector<vector<char>> & grid,int init_x,int init_y ){
grid[init_x][init_y]='0';
if(init_x>=1 && grid[init_x-1][init_y]=='1')dfs(grid,init_x-1,init_y);
if( init_x+1<grid.size() && grid[init_x+1][init_y]=='1')dfs(grid,init_x+1,init_y);
if(init_y>=1 && grid[init_x][init_y-1]=='1')dfs(grid,init_x,init_y-1);
if(init_y+1<grid[0].size() && grid[init_x][init_y+1]=='1')dfs(grid,init_x,init_y+1);
}
int numIslands(vector<vector<char>>& grid) {
if(grid.size()==0) return 0;
int row=grid.size();
int col=grid[0].size();
int res=0;
for(int i=0;i<row;i++){
for(int j=0;j<col;j++){
if(grid[i][j]=='1'){
res++;
dfs(grid,i,j);
}
}
}
return res;
}
};
75. 颜色分类
给定一个包含红色、白色和蓝色,一共 n 个元素的数组,原地对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。
此题中,我们使用整数 0、 1 和 2 分别表示红色、白色和蓝色。
注意:
不能使用代码库中的排序函数来解决这道题。
思路:参考
class Solution {
public:
void sortColors(vector<int>& nums) {
int p0=0;
int p2=nums.size()-1;
int curr=p0;
while(curr<=p2){
if(nums[curr]==0){
swap(nums[curr++],nums[p0++]);
}
else if(nums[curr]==2){
swap(nums[curr],nums[p2--]);
}
else curr++;
}
}
};
221. 最大正方形
在一个由 0 和 1 组成的二维矩阵内,找到只包含 1 的最大正方形,并返回其面积。
示例:
输入:
1 0 1 0 0
1 0 1 1 1
1 1 1 1 1
1 0 0 1 0
输出: 4
class Solution {
public:
int maximalSquare(vector<vector<char>>& matrix) {
if(matrix.size()==0|| matrix[0].size()==0)return 0;
int col=matrix[0].size();
int row=matrix.size();
vector<vector<int>>dp(row,vector<int>(col,0));
int res=0;
for(int i=0;i<row;i++){
for(int j=0;j<col;j++){
if(matrix[i][j]=='1'){
if(i==0||j==0){
dp[i][j]=1;
}
else{
dp[i][j]=min(min(dp[i-1][j],dp[i-1][j-1]),dp[i][j-1])+1;
}
res=max(dp[i][j],res);
}
}
}
return res*res;
}
};
76. 最小覆盖子串
给你一个仅由大写英文字母组成的字符串,你可以将任意位置上的字符替换成另外的字符,总共可最多替换 k 次。在执行上述操作后,找到包含重复字母的最长子串的长度。
注意:
字符串长度 和 k 不会超过 10^4。
思路:滑动窗口
class Solution {
public:
string minWindow_1(string s, string t) {
//最小字串的开始位置和最小长度
int start=0,minLength=INT_MAX;
unordered_map<char,int> needs;
unordered_map<char,int> window;
//建立字符串t的字符表
for(char c:t)needs[c]++;
//初始化窗口区间和记录窗口中满足的字符个数
int left=0,right=0,match=0;
//开始滑动窗口
while(right<s.size())
{
char c1=s[right];
if(needs.count(c1)){//字符c1存在于t的字符表中
window[c1]++;//加入window
if(window[c1]==needs[c1])//字符c1的个数已经满足字符表中的个数了
match++;
}
right++;
while(match==needs.size())
{
if(right-left<minLength){//窗口的大小小于最小长度,更新字符串
start=left;
minLength=right-left;
}
char c2=s[left];
if(needs.count(c2)){//c2在needs中,主要用来去除window中多余的字符数的
window[c2]--;//字符c2的个数减1
if(window[c2]<needs[c2])//字符c2出现次数不再符合要求
match--;
}
left++;//不管c2在不在needs中,都需要将left右移,因为此时的window的字符个数必然多于needs的字符个数
}
}
return minLength==INT_MAX?"":s.substr(start,minLength);
}
};
402. 移掉K位数字
给定一个以字符串表示的非负整数 num,移除这个数中的 k 位数字,使得剩下的数字最小。
注意:
num 的长度小于 10002 且 ≥ k。
num 不会包含任何前导零。
参考:地址
#include<iostream>
#include<bits/stdc++.h>
using namespace std;
class Solution {
public:
string removeKdigits(string num, int k) {
string res;
for(int i=0;i<num.size();i++){
while(res.size() && k && res.back()>num[i]){
res.pop_back();
k--;
}
if(res.size()==0 && num[i]=='0'){
continue;//跳过前置0
}
res+=num[i];
}
while(k>0 && !res.empty()){//当还要再移除数字的时候:从此时单调递增栈的top部删去数字
res.pop_back();
k--;
}
return res==""? "0":res;
}
};
int main(){
Solution sol;
string str="1432219";
string str1="123456";
string str2="10001001";
string res=sol.removeKdigits(str2,3);
int c=1;
}