编程题—面试必刷101题(c++)

编程题—面试必刷101题

牛客网 - 找工作神器|笔试题库|面试经验|实习招聘内推,求职就业一站解决_牛客网

代码随想录

☆数学

左移与右移/与运算

int i = 1;
i = i << 2; //把i里的值左移2位
//000...0001 左移两位变成000... 0100

//求二进制中1的个数
int hammingWeight(uint32_t n) {
        int ans=0;
        while(n){
            ans+=n&1;
            n>>=1;
        }
        return ans;        
    }
//巧妙应用n&(n−1)
//(n−1) 解析: 二进制数字 n最右边的 1变成 0,此 1右边的 0都变成 1。
//n&(n - 1)解析: 二进制数字 n最右边的 1变成 0,其余不变

int hammingWeight(uint32_t n) {
        int ans=0;
        while(n){
            n&=(n-1);//消除掉最右边的1
            ans++;
        }
        return ans;        
    }

二进制

可以转到字符串的第二题

//数组法 将整型用数组储存 然后将数组的值转为整型
int main()
{
    int  n;
    cin>>n;
    vector<int>ans;
    int ansz;
    while(n)
    {
        ans.push_back(n%2);
        n=n/2;
    }
    for(int j=ans.size()-1; j>=0 ; j--)
    {
       cout<<ans[j];
       ansz+=ans[j]*pow(10,j);
    }
    cout<<"ansz:"<<ansz;
    return 0;
}
//字符串法 将整型用数组储存 将数组的值转为整型太麻烦了 知道这个方法就行
int main()
{
    int  n;
    cin>>n;
    string s;
    while(n)
    {
        s+=(n%2==0?'0':'1') ;
        n/=2;
    }
    //反转字符串 两种方法皆可
    for(int i=0,j=s.size()-1; i<s.size()/2; i++,j--)
    {
        swap(s[i],s[j]);
    }
    //reverse(s.begin(),s.end());
    cout<<s<<endl;
    return 0;
}

最大公因素与最小公倍数

一个长度为n的数组[n1,n2…nn],求计算出他们的最大公因数

int cal_max_common_factor(int* L, int LLen) {//l是长度
        if(LLen==0) return -1;
        //求出数组中最小的那个元素
        vector<int>v;
        for(int i=0;i<LLen;i++){
            v.push_back(L[i]);          
        }
        sort(v.begin(),v.end());
        int minimum=v[0];
       // 以最小的那个元素当做最大公因子
        for(int i=minimum;i>0;i--){
            bool flag=true;
            //L数组中的元素去除,若有余数 则不是最大公因子
            for(int j=0;j<LLen;j++){
                if(L[j]%i!=0){
                    flag=false;
                    break;         
                }
            }
            if(flag==true) {return i;}
        }
        return 0;
    }
//辗转除余法
int gys(int a,int b){
        if(a==0||b==0) return 0;
        while(b!=0){
            int k=a%b;
            a=b;
            b=k;
        }
        return a;            
        }
    int cal_max_common_factor(int* L, int LLen) {
        // write code here
        if(LLen==0) return -1;
        int k;
        k=gys(L[0], L[1]);
        for(int i=2;i<LLen;i++){
            k=gys(k, L[i]);
        }
        return k;
        
    }

//最小公倍数  两个数的乘积/最大公约数
int gbs(int a,int b){
    int t=gys(a,b);
    return a*b/t;}

各位相加为个位数

258. 各位相加 - 力扣(LeetCode)

int main()
{
    int X;
    cin>>X;
    while(X>=10){
        int sum=0;
        while(X){
            sum+=X%10;
            X/=10;
        }
        X=sum;
    }

    cout <<X<< endl;
    return 0;
}

某一个数只经过*2与-1得到另一个数的最小操作数

int solution(int X, int  H) {
	int count = 0;
	while (X != H) {
		 if (X < H) {
				if (H < 2 *X-1) {
						X -= 1;
					}
					else  {
						X = 2 * X;
					}
         count++;
		}
		else if(X>H){
			count+=X-H;
             X=H;
		}

	}
	return count;
}
int main()
{
    int X,H;
    cin>>X>>H;
    int n=solution( X, H);
    cout << n<< endl;
    return 0;
}

字符串

左旋转字符串

剑指 Offer 58 - II. 左旋转字符串 - 力扣(LeetCode)

string reverseLeftWords(string s, int n) {
        //前n个翻转
        //n+1到s.size()翻转
        //全部翻转   
            reverse(s.begin(),s.begin()+n);
            reverse(s.begin()+n,s.begin()+s.size());
            reverse(s.begin(),s.begin()+s.size());
            return s;
    }

翻转字符串

剑指 Offer 58 - I. 翻转单词顺序 - 力扣(LeetCode)

344. 反转字符串 - 力扣(LeetCode)

string reverseWords(string s) {
        string res;
        int n = s.size();
        if(n == 0) return res;
        int right = n - 1;
        while(right >= 0){
            //从后往前寻找第一字符
            while(right >= 0 && s[right] == ' ') right--;
            if(right < 0) break;

            //从后往前寻找第一个空格
            int left = right;
            while( left >= 0 && s[left] != ' ' ) left--;

            //添加单词到结果
            res += s.substr(left + 1, right - left);
            res += ' ';

            //继续往前分割单词
            right = left;
        }
        //去除最后一个字符空格
        if (!res.empty()) res.pop_back();
        return res;
    }

 def reverseWords(self, s: str) -> str:
        return " ".join(reversed(s.split()))

void reverseString(vector<char>& s) {
        for(int i=0,j=s.size()-1;i<s.size()/2;i++,j--){
            swap(s[i],s[j]);
        }
//大小写翻转
for(int i=0;i<n;i++){//遍历 
		if(s[i]>='A'&&s[i]<='Z'){
				s[i]+='a'-'A';
			}
		else if(s[i]>='a'&&s[i]<='z'){
			s[i]-='a'-'A';
		}	
			cout<<s[i];
	}

判断是否是子序列

给定两个字符串 s和 t ,判断 s是否为 t 的子序列。字符串的一个子序列是原始字符串删除一些(也可以不删除)字符而不改变剩余字符相对位置形成的新字符串。(例如,"ace"是"abcde"的一个子序列,而"aec"不是)。

#include<iostream>
using namespace std;
bool help(string s, string t, int l1, int l2){
    if(l1 >= s.length()) return true;
    if(l2 >= t.length()) return false;
    if(s[l1] == t[l2]) return help(s, t, l1 + 1,l2 + 1); 
    else  return help(s, t, l1,l2 + 1);
}
int main(){
    string s,t;
    cin >> s >> t;
    if(help(s, t, 0, 0)) cout << "true";
    else cout << "false";
}

最短转化为a的字符串(蚂蚁笔试)

x个连续字母a组成字符串,两个连续相同的字母可以转换成其下一个相邻字母,问最短的可以转换成x个字母a的字符串

#include <iostream>
#include <algorithm>
#include<bits/stdc++.h>
using namespace std;
char letterMap[26] = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' };
int main()
{
    string res="";
    int x;
    cin>>x;
    while(x)
    {
        int tmp=x;
        int cnt=0;
        while(tmp)
        {
            tmp>>=1;
            cnt++;
        }
        x-=pow(2,cnt-1);
        res+=letterMap[cnt-1];

    }
    cout << res << endl;
    return 0;
}

//法二 转换为数组再求解
int main()
{
    int  n;
    cin>>n;
    vector<int>ans;
    string s;
    int ansz;
    while(n)
    {
        ans.push_back(n%2);
        n=n/2;
    }
    int j=ans.size()-1;
    while(j>=0)
    {
        if(ans[j]==1) {s+=(j+'a');j--;}
        else j--;
    }
    cout<<s<<endl;
    return 0;
}

多个空格转为1个空格(9.17深圳大普笔试)

将字符串中连续的多个空格替换成一个空格

int main()
{
    char str[]="    how       are   you     ";
    int i=0,j=0;//判断是否首字母为空格
    //删除开头为空格的情况
    while(str[i]!='\0'){
        if(str[i]!=' ')break;
        else i++;
    }
    //处理中间的空格 多个空格变为一个
    while(str[i]!='\0'){
        if(str[i]!=' ') str[j++]=str[i++];
        else{
            str[j++]=str[i++];
            while(str[i]==' ') i++;
            }
        }
    //处理最后的空格
    if(str[j-1]==' ') str[j-1]='\0';
    else str[j]='\0';
    int k=0;
    //将中间多余的空格删除,并将其中的空格变成其他字符
    while(str[k]!='\0'){
        if(str[k]==' ') str[k]=';';
    else k++;
    }
    cout<<str<<endl;
    return 0;
}

转换字符串的最少操作次数

2027. 转换字符串的最少操作次数 - 力扣(LeetCode)

把字符串中的‘X’转为‘O’;一次 操作 定义为从 s 中选出 三个连续字符 并将选中的每个字符都转换为 ‘O’ 。注意,如果字符已经是 ‘O’ ,只需要保持 不变;返回最少的操作次数

int minimumMoves(string s) {
        //从头遍历字符数组,如果该字符为'O'直接跳过,否则就对后面三个进行修改
        int n=s.size(),i=0,cnt=0;
        while(i<n){
            if(s[i]=='O') {i++;continue;}
            int k=3;
            while(k>0&&i<n){
                s[i]='O';
                i++;
                k--;
            }
            cnt++;
        }
        return cnt;     
    }

统计text.txt中单词总数,以及每个单词出现的次数 单词频率

面试题 16.02. 单词频率 - 力扣(LeetCode)

(单词之间以空格分隔 文章区分大小)

unordered_map<string,int> mydic;
    WordsFrequency(vector<string>& book) {
        for(string i:book)
            mydic[i]++;
    }
    int get(string word) {
        return m[word];
    }

有效字母异位词

242. 有效的字母异位词 - 力扣(LeetCode)

bool isAnagram(string s, string t) {
           //t 是 s 的异位词等价于「两个字符串中字符出现的种类和次数均相等」
           //定义一个新的数组record,大小为26,因为字符串中有26个小写字母
           //遍历s,每出现一个字母在相应的索引下标+1;遍历t,每出现一个字母在相应的索引下标-1;
           //如果record所有元素都为0,则返回true

           //定义一个新的数组record 初始化为0
           int record[26]={0};
           //遍历s,每出现一个字母在相应的索引下标+1;
           for(int i=0;i<s.length();i++){
               record[s[i]-'a']++;
           }
            //遍历t,每出现一个字母在相应的索引下标-1;
            for(int j=0;j<t.length();j++){
                record[t[j]-'a']--;
            }
            //判断record所有元素都为0,则返回true
            for(int k=0;k<26;k++){
                if(record[k]!=0)
                return false;
            }
            return true;

    }

有效的括号

20. 有效的括号 - 力扣(LeetCode)

//括号匹配是使用栈解决的经典问题
//不匹配的情况有三:左括号多余、括号类型匹配不上、右括号多余
//技巧:在匹配左括号的时候,右括号先入栈,就只需要比较当前元素和栈顶相不相等就可以了,比左括号先入栈代码实现要简单的多了!
    bool isValid(string s) {
        stack<int> st;
        for (int i = 0; i < s.size(); i++) {
            if (s[i] == '(') st.push(')');
            else if (s[i] == '{') st.push('}');
            else if (s[i] == '[') st.push(']');
            // 第三种情况:遍历字符串匹配的过程中,栈已经为空了,没有匹配的字符了,说明右括号没有找到对应的左括号 return false
            // 第二种情况:遍历字符串匹配的过程中,发现栈里没有我们要匹配的字符。所以return false
            else if (st.empty() || st.top() != s[i]) return false;
            else st.pop(); // st.top() 与 s[i]相等,栈弹出元素
        }
        // 第一种情况:此时我们已经遍历完了字符串,但是栈不为空,说明有相应的左括号没有右括号来匹配,所以return false,否则就return true
        return st.empty();
    }

动态规划

适合于很多重叠的子问题,动态规划中每一个状态一定是由上一个状态推导出来的(一般求多种可能性递推性质)

解题步骤

  • 确定dp数组(dp table)以及下标的含义:dp[i]的定义为:第i个数的斐波那契数值是dp[i]
  • 确定递推公式:如状态转移方程 dp[i] = dp[i - 1] + dp[i - 2];
  • dp数组如何初始化:dp[0] = 0;dp[1] = 1;
  • 确定遍历顺序:从前往后或从后往前
  • 举例推导dp数组

找问题的最好方式就是把dp数组打印出来,看看究竟是不是按照自己思路推导的!

做动规的题目,写代码之前一定要把状态转移在dp数组的上具体情况模拟一遍,心中有数,确定最后推出的是想要的结果。

爬楼梯的最小成本

剑指 Offer II 088. 爬楼梯的最少成本 - 力扣(LeetCode)

//基础
int minCostClimbingStairs(vector<int>& cost) {
        //dp[i]的定义:到达第i个台阶所花费的最少体力为dp[i]
        //公式dp[i] = min(dp[i - 1], dp[i - 2]) + cost[i];
      vector<int> dp(cost.size());
        dp[0] = cost[0];
        dp[1] = cost[1];
        for (int i = 2; i < cost.size(); i++) {
            dp[i] = min(dp[i - 1], dp[i - 2]) + cost[i];
        }
        // 注意最后一步可以理解为不用花费,所以取倒数第一步,第二步的最少值
        return min(dp[cost.size() - 1], dp[cost.size() - 2]);
    }
//进阶版
int minCostClimbingStairs(vector<int>& cost) {
        int n=cost.size();
        int dp0=cost[0],dp1=cost[1];
        for(int i=2;i<n;i++){
            int dpi=min(dp0,dp1)+cost[i];
            dp0=dp1;
            dp1=dpi;
        }
        return min(dp0,dp1);
    }
//斐波那契数列
//F(0) = 0,F(1) = 1
//F(n) = F(n - 1) + F(n - 2),其中 n > 1
int fib(int n) {
        if(n<2) return n;
        return fib(n-1)+fib(n-2);
    }
//进阶
int fib(int n) {
        if(n<2) return n;
        int dp0=0,dp1=1;
        for(int i=2;i<=n;i++){
            int sum=dp0+dp1;
            dp0=dp1;
            dp1=sum;
        }
        return dp1;
    }

三步问题

面试题 08.01. 三步问题 - 力扣(LeetCode)

int waysToStep(int n) {
       if(n<3)  return n;
       if(n==3) return 4;
       int dp1=1,dp2=2,dp3=4;
       int MOD=1000000007;
       for(int i=4;i<=n;i++){
           int dpn=((dp1+dp2)%MOD+dp3)%MOD;//前两个相加可能超限制
           dp1=dp2;
           dp2=dp3;
           dp3=dpn;
       }
       return dp3;
    }

连续子数组的最大和

剑指 Offer 42. 连续子数组的最大和 - 力扣(LeetCode)

输入一个整型数组,数组中的一个或连续多个整数组成一个子数组。求所有子数组的和的最大值。

int maxSubArray(vector<int>& nums) {
        int n=nums.size();
        int dp=nums[0];
        int ma=dp;
        for(int i=1;i<n;i++){
            dp=max(dp+nums[i],nums[i]);
            ma=max(dp,ma);
        }
        return ma;

    }

BM64 最小花费爬楼梯

最小花费爬楼梯_牛客题霸_牛客网 (nowcoder.com)

int minCostClimbingStairs(vector<int>& cost) {
        // write code here
        int n=cost.size();
        int dp0=cost[0],dp1=cost[1];//初始化
        for(int i=2;i<n;i++){
            int dpi=min(dp0,dp1)+cost[i];//递推序列
            dp0=dp1;
            dp1=dpi;
        }
        return min(dp0,dp1);  
    }

BM65 最长公共子序列(二)/及长度

最长公共子序列(二)_牛客题霸_牛客网 (nowcoder.com)

剑指 Offer II 095. 最长公共子序列 - 力扣(LeetCode)

子序列:不要求位置在原串中连续,例如:“ace” 是 “abcde” 的子序列,但 “aec” 不是 “abcde” 的子序列

二维动态规划问题

在这里插入图片描述

//最长公共子序列 具体值
//方法一 动态规划记下字符串 内存超限制 一组用例不过
string LCS(string s1, string s2) {
        // write code here
        int  m=s1.size(),n=s2.size();
        vector<vector<string>>dp(m+1,vector<string>(n+1));//因为要加1行0以及一列0
        if(m==0||n==0) return "-1";
        for(int i=1;i<=m;i++){
            char c1=s1.at(i-1);
            for(int j=1;j<=n;j++){
                char c2=s2.at(j-1);
                if(c1==c2) {
                    dp[i][j]=dp[i-1][j-1]+s1.at(i-1);//若相等 则加上斜对角的值
                }
                else {
                    //dp[i][j]=max(dp[i-1][j],dp[i][j-1]);//不相等,则左边和上边取最大值
                     dp[i][j]=dp[i-1][j].length()>dp[i][j-1].length()?dp[i-1][j]:dp[i][j-1];
                }
                    
            }
        }
        if(dp[m][n]=="") return "-1";
        return dp[m][n];
    }

//方法二 存长度,再反查得到字符串,ok!
string LCS(string s1, string s2) {
        // write code here
        int  m=s1.size(),n=s2.size();
        vector<vector<int>>dp(m+1,vector<int>(n+1));//因为要加1行0以及一列0
        if(m==0||n==0) return "-1";
        string ans;
        //存取最长长度
        for(int i=1;i<=m;i++){
            char c1=s1.at(i-1);
            for(int j=1;j<=n;j++){
                char c2=s2.at(j-1);
                if(c1==c2) {
                    dp[i][j]=dp[i-1][j-1]+1;//若相等 则加上斜对角的值
                }
                else {
                    dp[i][j]=max(dp[i-1][j],dp[i][j-1]);//不相等,则左边和上边取最大值
                }
                    
            }
        }
        //反查得到字符串
        for(int i=m,j=n;dp[i][j]>=1;){
            if(s1[i-1]==s2[j-1]){
                ans+=s1[i-1];
                --i;
                --j;
            }
            else if(dp[i-1][j]>=dp[i][j-1]) --i;
            else --j;
            
        }
        reverse(ans.begin(), ans.end());
        return ans.empty()?"-1":ans;
    }
//最长公共子序列的长度
int longestCommonSubsequence(string text1, string text2) {
        int  m=text1.size(),n=text2.size();
        vector<vector<int>>dp(m+1,vector<int>(n+1));//因为要加1行0以及一列0
        for(int i=1;i<=m;i++){
            char c1=text1.at(i-1);
            for(int j=1;j<=n;j++){
                char c2=text2.at(j-1);
                if(c1==c2) dp[i][j]=dp[i-1][j-1]+1;//若相等 则斜对角+1
                else dp[i][j]=max(dp[i-1][j],dp[i][j-1]);//不相等,则左边和上边取最大值

            }
        }
        return dp[m][n];
    }

最长公共子串

最长公共子串_牛客题霸_牛客网 (nowcoder.com)

string LCS(string str1, string str2) {
         // write code here
        int  m=str1.size(),n=str2.size();
        vector<vector<int>>dp(m+1,vector<int>(n+1));//因为要加1行0以及一列0
        int max=0,pos=0;
        if(m==0||n==0) return "-1";
        //存取最长长度
        for(int i=1;i<=m;i++){
            char c1=str1.at(i-1);
            for(int j=1;j<=n;j++){
                char c2=str2.at(j-1);
                if(c1==c2) {
                    dp[i][j]=dp[i-1][j-1]+1;//若相等 则加上斜对角的值
                }
                else {
                    dp[i][j]=0;//不相等,则赋值为0
                }
                //更新最大长度
                if(dp[i][j]>max){
                    max=dp[i][j];
                    pos=i-1;
                }
                    
            }
        }
        return str1.substr(pos-max+1,max);
    }

BM71 最长上升子序列(一)

最长上升子序列(一)_牛客题霸_牛客网 (nowcoder.com)

int LIS(vector<int>& arr) {
        // write code here
        int n=arr.size();
        vector<int>dp(n,1);//初始化为1
        int res=0;//最大长度
        for(int i=0;i<n;i++){
            for(int j=0;j<i;j++){
                 //如果前面的数小于当前arr[i],则以当前数字结尾的最长上升子序列可能更新
                if(arr[i]>arr[j]) dp[i]=max(dp[j]+1,dp[i]);
            }            
        }
        for(int i=0;i<n;i++){
            if(dp[i]>res) res=dp[i];
        }
       return res; 
    }

最长回文子串

最长回文子串_牛客题霸_牛客网 (nowcoder.com)

//中心扩散法
int expandAroundCenter(string s, int left, int right)
	{
		int L = left, R = right;
		while (L >= 0 && R < s.length() && s[L] == s[R])
		{// 计算以left和right为中心的回文串长度
			L--;
			R++;
		}
		return R - L - 1;
	}
   string longestPalindrome(string s) 
	{
		if (s.length() < 1)
		{
			return "";
		}
		int start = 0, end = 0;
		for (int i = 0; i < s.length(); i++)
		{
			int len1 = expandAroundCenter(s, i, i);//一个元素为中心
			int len2 = expandAroundCenter(s, i, i + 1);//两个元素为中心
			int len = max(len1, len2);
			if (len > end - start)
			{
				start = i - (len - 1) / 2;
				end = i + len / 2;
			}
		}
		return s.substr(start, end - start + 1);
	}

    int getLongestPalindrome(string A) {
        // write code here
        int n=A.size();
       string s=longestPalindrome(A);
        return s.size();
    }

背包问题

01背包、完全背包->(物品个数的不同)->应用->暴力,dp(一维 二维)
(0,i)的物品放进容量为j的背包里

在这里插入图片描述

数组

三色球

三色球_讨论帖_牛客网 (nowcoder.com)

最小没出现的正整数

给定一个无序的正整数数组,输出数组中没有出现过的最小正整数。比如[1,2,4] 返回 3,时间复杂度O(n)时间。

268. 丢失的数字 - 力扣(LeetCode)

//排序的时间复杂度是O(nlogn),寻找的时间复杂度是O(n),因此是O(nlogn)
int missingNumber(vector<int>& nums) {
        sort(nums.begin(),nums.end());
        int n = nums.size();
        for (int i = 0,j=1; i <n,j<=n; i++,j++) {
            if (nums[i] != j) {
                return j;
            }
        }
        return n+1;
    }
//将数组的元素加入到哈希集合中,依次检查1-n的每个整数是否在哈希集合中
//哈希集合的每次添加元素和查找元素的时间复杂度都是 O(1),因此总时间复杂度是 O(n)。
int missingNumber(vector<int>& nums) {
        unordered_set<int> set;
        int n = nums.size();
        for (int i = 0; i < n; i++) {
            set.insert(nums[i]);
        }
        int missing = -1;
        for (int i = 1; i <= n; i++) {
            if (!set.count(i)) {
                missing = i;
                break;
            }
        }
        return missing;
    }

合并排序的数组

面试题 10.01. 合并排序的数组 - 力扣(LeetCode)

//直接合并后排序 没有利用两个数组已经排序的优势
void merge(vector<int>& A, int m, vector<int>& B, int n) {
        for (int i = 0; i < n; ++i) {
            A[m + i] = B[i];
        }
        sort(A.begin(), A.end());
    }
//双指针  将两个数组看作队列,每次从两个数组头部取出比较小的数字放到结果中,slow作呕一部,fast走两步
    void merge(vector<int>& A, int m, vector<int>& B, int n) {
        int a=0,b=0;//当做队列的头部指针
        int sor[m+n],cur;
        while(a<m||b<n){
            if(a==m) cur=B[b++];
            else if(b==n) cur=A[a++];
            else if(A[a]<B[b]) cur=A[a++];
            else cur=B[b++];
            sor[a+b-1]=cur;
        }
        for(int i=0;i<m+n;i++){
            A[i]=sor[i];
        }
    }

数组相对排序

剑指 Offer II 075. 数组相对排序 - 力扣(LeetCode)


    vector<int> relativeSortArray(vector<int>& arr1, vector<int>& arr2) {
//统计arr1中元素出现的次数
        int upper = *max_element(arr1.begin(), arr1.end());
        vector<int> frequency(upper + 1);
        for (int x: arr1) {
            ++frequency[x];
        }
        vector<int> ans;
//arr2按照插入
        for (int x: arr2) {
            for (int i = 0; i < frequency[x]; ++i) {
                ans.push_back(x);
            }
            frequency[x] = 0;
        }
//此时还剩下没在arr2中出现的元素
        for (int x = 0; x <= upper; ++x) {
            for (int i = 0; i < frequency[x]; ++i) {
                ans.push_back(x);
            }
        }
        return ans;
    }

两数之和

1. 两数之和 - 力扣(LeetCode)

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        std::unordered_map <int,int> map;
        for(int i = 0; i < nums.size(); i++) {
            auto iter = map.find(target - nums[i]);//自动类型判断
            if(iter != map.end()) {
                return {iter->second, i};//iter.first会得到key,iter.second会得到value。 // 如果差值已经存在过,直接返回对应的索引
            }
            map.insert(pair<int, int>(nums[i], i));//在map中插入找到的元素 // 否则存起来
        }
        return {};
    }
};

查找插入的位置

剑指 Offer II 068. 查找插入位置 - 力扣(LeetCode)

int searchInsert(vector<int>& nums, int target) {
        //成立的条件nums[pos−1]<target≤nums[pos]
        //即在一个有序数组中找第一个大于等于 target 的下标
        int l=0,h=nums.size()-1,ans=nums.size();//ans 初值设置为数组长度可以省略边界条件的判断
        while(l<=h){
            int m=l+(h-l)/2;
            if(nums[m]>=target) {
            ans=m;
            h=m-1;
            }
            else l=m+1;
        }
        return ans;
    }

字符串中的变位词

剑指 Offer II 014. 字符串中的变位词 - 力扣(LeetCode)

//方法一:滑动窗口
bool checkInclusion(string s1, string s2) {
        //变位词即字符个数相等即可
        //记 s1 的长度为 n,我们可以遍历 s2中的每个长度为 n的子串,判断子串和 s1 中每个字符的个数是否相等
        int n = s1.length(), m = s2.length();
        if (n > m) return false;
        vector<int>cnt1(26,0),cnt2(26,0);
        //先记录前两个字符
        for(int i=0;i<n;i++){
            cnt1[s1[i]-'a']++;
            cnt2[s2[i]-'a']++;
        }
        
        if(cnt1==cnt2) return true;
        //开始接下来的字符  cnt2开始往右滑动 右边+,左边- 始终保持滑动窗口为2
        for(int j=n;j<m;j++){
            cnt2[s2[j]-'a']++;
            cnt2[s2[j-n]-'a']--;
            if(cnt1==cnt2) return true;
        }
        return false;
    }

最小操作次数(美团9.17笔试)

最少操作数使数组递增

输入n和数组的值,最少需要多少次操作可以把数组变成顺子。

比如3。3 7 6 输出2;即经过两次操作可以变成5 6 7

#include<bits/stdc++.h>
using namespace std;
int main(){
  int n;
  cin>>n;
  vector<int> vec;
  int ans=0;
  for(int i=0;i<n;i++){
    int ii;
    cin>>ii;
    vec.push_back(ii);
  }
  sort(vec.begin(),vec.end());
  int m1=vec.size()/2;
  int m=vec[m1];
  int mi=m-m1;//顺子中最小的值;
  vector<int> vec1;//存去重后的数组
  for(int i=0;i<n;i++){
    ans+=abs(vec[i]-mi);
    mi++;
  }
  cout<<ans<<endl;
  return 0;
}

呜呜呜 我在力扣找到了类似的 1827. 最少操作使数组递增 - 力扣(LeetCode)

数组原有的位置顺序不能变

int minOperations(vector<int>& nums) {
       int ans=0,temp;
       int n=nums.size();
       if(n==1) return 0;
       for(int i=1;i<n;i++){
           if(nums[i]<=nums[i-1]){
               temp=nums[i-1]-nums[i]+1;
               nums[i]+=temp;
               ans+=temp;
           }
       }
       return ans;
    }

最小操作次数使得数组元素相等

453. 最小操作次数使数组元素相等 - 力扣(LeetCode)

每次操作都会使得n-1个元素增加1

int minMoves(vector<int>& nums) {
      //只需要考虑数组中元素相对大小的变化
      //使 n−1 个元素增加 1,也可以理解使 1个元素减少 1
      //计算使得所有元素减少到最小值所需的次数
      int n=nums.size(),ans=0;
      //求最小值的方法
      //方法一
    //   sort(nums.begin(),nums.end());
    //   int mi=nums[0];
    //方法二
      //int mi=INT_MAX;
     // for(int i=0;i<n;i++) mi=min(mi,nums[i]);
     //方法三
     int  mi=*min_element(nums.begin(),nums.end());
      for(int i=0;i<n;i++) ans+=nums[i]-mi;
      return ans;
    }

数组内乘积小于k的数(百度笔试)-滑动窗口

剑指 Offer II 009. 乘积小于 K 的子数组 - 力扣(LeetCode)

int numSubarrayProductLessThanK(vector<int>& nums, int k) {
        int l=0,r=0,n=nums.size(),ans=0;
        int cur=1;
        while(l<=r&&r<n){
            cur*=nums[r];
            while(l<=r&&cur>=k){
                cur/=nums[l];
                l++;
            }
            ans+=r-l+1;
            r++;
        }
         return ans;
    }

链表

链表反转

206. 反转链表 - 力扣(LeetCode)

ListNode* reverseList(ListNode* head) {
        //双指针法 从前往后翻转指向
      //cur指针,指向头结点,再定义一个pre指针,初始化为null
     //while循环中翻转&cur和pre指针更新
        ListNode*tmp;//暂存
        ListNode*cur=head;//头指针赋值给cur
        ListNode*pre=NULL;
        while(cur){//当目前的指针不为空 翻转操作
        tmp=cur->next;
        cur->next=pre;
        //更新
        pre=cur;
        cur=tmp;
        }
        return pre;
    }

判断链表的环并找出环节点BM6 +BM7

BM6 判断链表中是否有环

判断链表中是否有环_牛客题霸_牛客网 (nowcoder.com)

step 1:设置快慢两个指针,初始都指向链表头。
step 2:遍历链表,快指针每次走两步,慢指针每次走一步。
step 3:如果快指针到了链表末尾,说明没有环,因为它每次走两步,所以要验证连续两步是否为NULL。
step 4:如果链表有环,那快慢双指针会在环内循环,因为快指针每次走两步,因此快指针会在环内追到慢指针,二者相遇就代表有环。

bool hasCycle(ListNode *head) {
        if(head==NULL) return false;//判断链表为空的情况
        //定义快慢指针
        ListNode*f=head;
        ListNode*s=head;
        //若没有环快指针会先走到链表尾部;
        while(f!=NULL && f->next !=NULL){
            f=f->next->next;//快指针走两步;
            s=s->next;//慢指针走一步
            if(f==s)return true;//相遇有环
        }
        return false;//到末尾没有环      
    }

BM7 链表中环的入口结点

链表中环的入口结点_牛客题霸_牛客网 (nowcoder.com)

剑指 Offer II 022. 链表中环的入口节点 - 力扣(LeetCode)

//方法一 哈希表
    ListNode *detectCycle(ListNode *head) {
        unordered_set<ListNode *> visited;
        while (head != nullptr) {
            //对特定元素进行计数,若重复则返回1,否则返回0
            if (visited.count(head))  return head;
            visited.insert(head);
            head = head->next;
        }
        return nullptr;
    }
//方法二 快慢指针
    ListNode *detectCycle(ListNode *head) {
        if(head==NULL) return NULL;//判断链表为空的情况
        //定义快慢指针
        ListNode*f=head; ListNode*s=head;
        //若没有环快指针会先走到链表尾部;
        while(f!=NULL && f->next !=NULL){
            f=f->next->next;//快指针走两步;
            s=s->next;//慢指针走一步
            if(f==s){
                //ptr和slow相遇的位置就是入环点,slow是顺时针走,ptr是从表头出发
                ListNode*ptr=head;
                while(ptr!=s){
                    ptr=ptr->next;
                    s=s->next;
                }
                return ptr;
        }
        }
        return NULL;//到末尾没有环 
    }

两个链表是否相交

遍历链表headA,并将链表 headA 中的每个节点加入哈希集合中。然后遍历链表 headB,对于遍历到的每个节点,判断该节点是否在哈希集合中:

如果当前节点不在哈希集合中,则继续遍历下一个节点;

如果当前节点在哈希集合中,则后面的节点都在哈希集合中,即从当前节点开始的所有节点都在两个链表的相交部分,因此在链表headB 中遍历到的第一个在哈希集合中的节点就是两个链表相交的节点,返回该节点。

如果链表headB 中的所有节点都不在哈希集合中,则两个链表不相交,返回null。

https://leetcode.cn/problems/intersection-of-two-linked-lists-lcci/

//法一:哈希表
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        unordered_set<ListNode*>visited;
        while(headA!=nullptr){
            visited.insert(headA);
            headA=headA->next;
        }
        while(headB!=nullptr){
            if(visited.count(headB)) return headB;
            headB=headB->next;
        }
        return nullptr;     
    }
//法二:双指针
设「第一个公共节点」为 node ,「链表 headA」的节点数量为 a ,「链表 headB」的节点数量为 bb,
「两链表的公共尾部」的节点数量为 c 
构建两个节点指针 A , B 分别指向两链表头节点 headA , headB
此时指针 A , B 重合,并有两种情况:a+(b−c)=b+(a−c)
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        ListNode *A = headA, *B = headB;
        while (A != B) {
            A = A != nullptr ? A->next : headB;
            B = B != nullptr ? B->next : headA;
        }
        return A;  
    }

最小栈

155. 最小栈 - 力扣(LeetCode)

class MinStack {
private:
   stack<int>st;
   stack<int>st_min;

public:
    MinStack() {
        st_min.push(INT_MAX);//必须初始化
    } 
    void push(int val) {
        st.push(val);
        if(st_min.top()>=val) st_min.push(val);
    }
    void pop() {
        if(st.top()==st_min.top()) st_min.pop();
        st.pop();
    } 
    int top() {
        return st.top();
    } 
    int getMin() {
        return st_min.top();
    }
};

模拟:边界与实际

BM97 旋转数组

旋转数组_牛客题霸_牛客网 (nowcoder.com)

类似于三次翻转,左右两边各翻转一次,整体再翻转一次。需要考虑m>n的情况

vector<int> solve(int n, int m, vector<int>& a) {
        // write code here
        m=m%n;
        reverse(a.begin(), a.end());
        reverse(a.begin(), a.begin()+m);
        reverse(a.begin()+m, a.end());
        return a;
    }

旋转数组中的最小数字

即寻找右排序的首个元素,即寻找旋转点,前面的元素小于后一个,那么后一个即为旋转点。

剑指 Offer 11. 旋转数组的最小数字 - 力扣(LeetCode)

int minArray(vector<int>& numbers) {
        for(int i=1;i<numbers.size();i++){
            if(numbers[i]<numbers[i-1]) return numbers[i];
        }
       return numbers[0];
    }

BM98 螺旋矩阵

给你一个正整数 n,生成一个包含 1n x n所有元素,且元素按顺时针顺序螺旋排列的 n x n
正方形矩阵 matrix

螺旋矩阵_牛客题霸_牛客网 (nowcoder.com)

在这里插入图片描述

class Solution {
public:
    vector<vector<int>> generateMatrix(int n) {
        if(n==0) return {};//为空则返回空
        // 创建大小固定的二维矩阵
        vector<vector<int>> matrix(n,vector<int>(n,0));
        int l=0,r=n-1,t=0,b=n-1;//上 右 下 左
        int cnt=1;//初始化
        while(cnt<=n*n){
            //向右
           for(int i=l;i<=r;i++) matrix[t][i]=cnt++;
           if(++t>b) break;
            //向下
           for(int i=t;i<=b;i++) matrix[i][r]=cnt++;
           if(--r<l) break;
            //向左
           for(int i=r;i>=l;i--) matrix[b][i]=cnt++;
           if(--b<t) break;
            //向上
           for(int i=b;i>=t;i--) matrix[i][l]=cnt++;
           if(++l>r) break;
        }
        return matrix;

    }
};

顺时针打印矩阵

输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字

https://leetcode-cn.com/problems/spiral-matrix/

思路没问题,注意边界值,以及i值的书写与加加减减

在这里插入图片描述

class Solution {
public:
    vector<int> spiralOrder(vector<vector<int> > &matrix) {
        if(matrix.empty()) return {};//为空则返回空
        int l=0,r=matrix[0].size()-1,t=0,b=matrix.size()-1;//上 右 下 左
        vector<int> ans;//记录答案;
        while(true){
            //向右
           for(int i=l;i<=r;i++) ans.push_back(matrix[t][i]);
           if(++t>b) break;
            //向下
           for(int i=t;i<=b;i++) ans.push_back(matrix[i][r]);
           if(--r<l) break;
            //向左
           for(int i=r;i>=l;i--) ans.push_back(matrix[b][i]);
           if(--b<t) break;
            //向上
           for(int i=b;i>=t;i--) ans.push_back(matrix[i][l]);
           if(++l>r) break;
        }
        return ans;
        
       
    }
};

BM98 顺时针旋转矩阵

有一个nxn整数矩阵,请编写一个算法,将矩阵顺时针旋转90度,并输出旋转后的矩阵。

顺时针旋转矩阵_牛客题霸_牛客网 (nowcoder.com)

//按列倒序存取
vector<vector<int> > rotateMatrix(vector<vector<int> > mat, int n) {
        vector<vector<int> >ans;
        vector<int>ans1;
        for(int i=0;i<n;i++){
            for(int j=n-1;j>=0;j--){
                ans1.push_back(mat[j][i]);
            }
            ans.push_back(ans1);
            ans1.clear();
        } 
        return ans;
    }
//对角线交换 再将元素内部翻转
vector<vector<int> > rotateMatrix(vector<vector<int> > mat, int n) {
        // write code here
        for (int i=0;i<n;++i){
            for (int j=0;j<i;++j){
                swap(mat[i][j],mat[j][i]);//先交换
            }
        }
        for (int i=0;i<n;++i)
            reverse(mat[i].begin(),mat[i].end());//再将内部元素翻转
        return mat;
    }

扑克牌中的顺子

从若干副扑克牌中随机抽 5 张牌,判断是不是一个顺子,即这5张牌是不是连续的。2~10为数字本身,A为1,J为11,Q为12,K为13,而大、小王为 0 ,可以看成任意数字。A 不能视为 14。
链接:https://leetcode.cn/problems/bu-ke-pai-zhong-de-shun-zi-lcof

思路:要保证5张牌是顺子,1.除大小王外,其他无重复;2.除大小王外,最大为max,最小为min,max-min<5.

1.遍历,遇到大小王就跳过;2.判重,set的时间复杂度为O(1);3,获取最大最小牌

class Solution {
public:
    bool IsContinuous( vector<int> numbers ) {
        set<int>repeat;//去重集合
        int max=0,min=14;//最大值最小值
        for(int i:numbers){//遍历找最大值、最小值 去重
            if(i==0) continue;//跳过大小王
            max=max>i?max:i;
            min=min<i?min:i;
            if(repeat.find(i)!=repeat.end()) return false;//若有重复,提前返回false
            repeat.insert(i);//没有重复,添加到set中
        }
        return max-min<5;
    }
};

蜗牛往上爬

一口井深len米,蜗牛白天爬m米,晚上滑下去n米,几天到井口?

int daycost(int len, int m, int n) {
        if(m<=n&&len>m) return -1;//注意处理好边界问题,
        //if(len<=m||len==0) return 1;
        int day=0;
        while(len>0){
            day+=1;
            len-=m;
            if(len<=0) return day;
            len+=n;
        }
        return 0;     
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Zlionheart

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值