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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值