2022-02-12剑指15-21(位运算)

面试题15

牛客网链接
思路1:书中常规解法

class Solution {
public:
     int  NumberOf1(int n) {
         int count=0;
         int flag=1;
         while(flag){
             if (n & flag){
                 ++count;
             }
             flag = flag<< 1;
             //注意左移的时候要更新flag
             //循环次数到flag不能左移为止,也就是int的长度,32位就是32次循环
         }
         return count;
     }
};

思路2:
一个整数,减去1后再和原来的数位与,相当于把最右边的1变成0,这个方法循环次数是原整数里面1的个数

class Solution {
public:
     int  NumberOf1(int n) {
         int count=0;
         
         while(n){
             ++count;
             n = n & (n-1);
         }
         return count;
     }
};

能否把移位换成乘除:不能,移位效率高于乘除,尽可能移位代替乘除法。
位运算可以参考这个题解,位运算要考虑负数的表示。

面试题16

思路1:
暴力

class Solution {
public:
    double Power(double base, int exponent) {
    //base是double,exponent是int,所以要考虑exponent是负数和0的情况
        if(exponent<0){
            base = 1/base;
            exponent = -exponent;
        }
        if(exponent==0){
        //边界,0次方都返回1
        	return 1;
        }
        double result = 1.0;
        while(exponent){
            result = result * base;
            exponent -= 1;
        }
        return result;
    }
};

时间复杂度O(n),空间复杂度O(1)

参考题解
思路2:
快速幂

class Solution {
public:
    double Power(double base, int exponent) {
    //base是double,exponent是int,所以要考虑exponent是负数和0的情况
        if(exponent<0){
            base = 1/base;
            exponent = -exponent;
        }
        if(exponent==0){
        //边界,0次方都返回1
        	return 1;
        }
        double result = 1.0;
        result = Power(base, exponent/2);
        if(exponent & 1){
            //奇数
            //奇数和1位与是正数,偶数和1位与是0
            result = result * result * base;
        }
        else{
            result = result * result;
        }
        return result;
    }
};

时间复杂度O(logn)
空间复杂度O(logn)

快速幂要背

非递归快速幂,空间复杂度O(1)

class Solution {
public:
    double Power(double base, int exponent) {
    //base是double,exponent是int,所以要考虑exponent是负数和0的情况
        if(exponent<0){
            base = 1/base;
            exponent = -exponent;
        }
        if(exponent==0){
        //边界,0次方都返回1
        	return 1;
        }
        double result = 1.0;
        while(exponent){
            if(exponent&1){
                result*=base;
                //1就乘进答案
            }
            base *= base;
            exponent >>= 1;
        }
        return result;
    }
};

相当于遍历n的二进制位,是1就乘进结果

面试题17

牛客网链接

class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param n int整型 最大位数
     * @return int整型vector
     */
    vector<int> printNumbers(int n) {
        // write code here
        long max = pow(10,n);
        vector<int> result;
        for(int i=1; i<max; ++i){
            result.push_back(i);
        }
        return result;
    }
};

在这里插入图片描述

面试题18

牛客网链接
牛客网此题和书上不同,这里按牛客网版本

class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param head ListNode类 
     * @param val int整型 
     * @return ListNode类
     */
    ListNode* deleteNode(ListNode* head, int val) {
        // write code here
        ListNode* flag=new ListNode(-1);
        //这里,新建节点的代码要记一下,不赋值的话会报错
        //因为要删除的节点可能是head,所以先在head前加一个节点
        flag->next = head;
        if(head->val == val){
            //这种单独判断head是不是等于val的方法其实不需要用一个flag
            flag->next=head->next;
            return flag->next;
        }
        while(flag->next){
            if(flag->next->val==val){
                flag->next=flag->next->next;
            }
            flag=flag->next;
        }
        return head;
        
    }
};

面试题19

这题先要会递归解法,然后看懂官方题解的文字部分,再会写第一个。
dp写的最清楚的题解

class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param str string字符串 
     * @param pattern string字符串 
     * @return bool布尔型
     */
    bool match(string str, string pattern) {
        string s=str, p=pattern;
        int m=s.size(), n=p.size();
        vector<vector<bool>> dp(m+1, vector<bool>(n+1, 0));
        dp[0][0]=1;
        for(int j=2; j<n+1; j+=2){
            dp[0][j]=(dp[0][j-2] && p[j-1] == '*');
        }
        //初始化主要针对0行0列,0行已经处理过,0列其实p是空串的时候,s不空都是false,所以不用特别处理
        //后面就从1行1列开始算了
        for(int i=1;i<m+1;++i)
            for(int j=1;j<n+1;++j){
                if(p[j-1]=='*')
                    dp[i][j] = dp[i][j-2] || 
                    (dp[i-1][j] && s[i-1]==p[j-2]) || 
                    (dp[i-1][j] && p[j-2]=='.');
                else
                    dp[i][j] = (dp[i-1][j-1] && s[i-1]==p[j-1]) || 
                    (dp[i-1][j-1] && p[j-1]=='.');
            }
        return dp[m][n];
    }
};

题解链接
DP思路就是转移方程->初始条件,转移方程要不漏。

class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param str string字符串 
     * @param pattern string字符串 
     * @return bool布尔型
     */
    bool match(string str, string pattern) {
        int n=str.size();
        int m=pattern.size();
        
        vector<vector<bool>> f(n+1, vector<bool>(m+1, 0));
        //注意vector定义,初始化为全0
        for(int i=0; i<=n; i++){
            //0是判断空串的,实际上的字符比较是1 to n
            for(int j=0; j<=m; j++){
                if(j==0){
                    f[i][j]=(i==0);//i==0就是true,否则false
                }
                else{
                    if(pattern[j-1] != '*'){
                        if(i > 0 && (str[i-1] == pattern[j-1] || pattern[j-1] == '.')){
                            f[i][j]=f[i-1][j-1];
                        }
                    }
                    else{
                        //不看,即不是连续c
                        if(j>=2){
                            f[i][j] = f[i][j] || f[i][j-2];
                        }//这么写是因为可以先默认这个,再走下面流程
                        //f[i][j]就是str i长度,pattern j长度能否匹配上,能匹配上就是true
                        if(i>=1 && j>=2 && (str[i-1] == pattern[j-2] || pattern[j-2] == '.')){
                            f[i][j] = f[i][j] || f[i-1][j];// patter[j-2]是c,[j-1]是*
                        }
                            //看,是连续c,>=1就是不能动已经赋值的f[0][j]
                    }
                }
            }
        }
        return f[n][m];
    }
};

递归解法

class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param str string字符串 
     * @param pattern string字符串 
     * @return bool布尔型
     */
    bool match(string str, string pattern) {
        string s=str, p=pattern;
        int m=s.size(), n=p.size();
        if(n==0){
            return m==0;
        }
        if(m==0){
            if(n%2 !=1 ){
                for(int i=1; i<n; i+=2){
                    if(p[i]!='*')
                        return false;
                }
                return true;
            }
            return false;
        }
        char c1=s[0], c2=p[0], c3='a';
        if(n>1) c3=p[1];
        if(c3 != '*'){
            if(s[0]==p[0] || p[0]=='.')
                return match(s.substr(1), p.substr(1));
            else return false;
        }
        else{
            if(match(s, p.substr(2))) return true;
            else{
                if(s[0]==p[0] || p[0]=='.')
                    return match(s.substr(1), p);
                else return false;
            }
        }
        //return false;
    }
};

官方题解
官方题解里面 [&]就是匿名函数,写在外面也可以
这个match小函数,就是把’.'和==并到一起,因为这俩其实处理方法一样

面试题20

题解链接
输入输出分析:str的每一位,只能是数字,’.’,'±’两个一样,'eE’两个一样,空格,其余字符都是false,且空格必须在首尾,其余位置也是false
去掉首尾空格以后逐个扫描str,
数字:直接往后
e/E:前面不能有e/E,上一位要有数,把dotSeen置为false
. 前面不能有. 不能有e/E 后面必须是数字
± 只能0位或者e/E后面一位 且后面要是.或者数字

这个自己写的有冗余,对着返回报错逐个补逻辑改出来的。

class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param str string字符串 
     * @return bool布尔型
     */
    //输入输出分析:str的每一位,只能是数字,'.','+-'两个一样,'eE'两个一样,空格,其余字符都是false,且空格必须在首尾,其余位置也是false
    //去掉首尾空格以后逐个扫描str,
    //数字:直接往后
    //e/E:前面不能有e/E,上一位要有数,把dotSeen置为false
    //.:前面不能有. 不能有e/E 后面必须是数字
    //+- 只能0位或者e/E后面一位 且后面要是.或者数字
    bool isNumeric(string str) {
        //先去掉首尾空格
        if(str.size() == 0) return false;
        str.erase(0, str.find_first_not_of(" "));
        str.erase(str.find_last_not_of(" ")+1);
        if(str.size() == 0) return false;
        //然后遍历str
        bool dotSeen = false;
        bool eSeen = false;
        bool numSeen = false;
        for(int i=0; i<str.size(); ++i){
            if(isdigit(str[i])){
                numSeen=true;
            }
            else if(str[i]=='e' || str[i]=='E'){
                dotSeen=false;
                numSeen=true;
                if(eSeen) return false;
                if(i==0) return false;
                if(i==str.size()-1) return false;
                eSeen=true;
            }
            else if(str[i] == '.'){
                if(dotSeen||eSeen) return false;
                if(!numSeen && (i==str.size() || !isdigit(str[i+1]))) return false;
                if(i!=str.size()-1 && !isdigit(str[i+1]) && str[i+1]!='e' && str[i+1]!='E') return false;
                dotSeen=true;
            }
            else if(str[i]=='-'||str[i]=='+'){
                if(i==str.size()-1) return false;
                if(!isdigit(str[i+1]) && str[i+1]!='.') return false;
                if(i!=0){
                    if(str[i-1]!='e' && str[i-1]!='E')
                        return false;
                }
            }
            else return false;
        }
        return true;
    }
};

面试题21

这题leetcode和书上一样,牛客和书上不一样,牛客多一个奇数偶数相对顺序不变,这里按牛客的写
牛客网链接
时间O(n) 空间O(n)

class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param array int整型vector 
     * @return int整型vector
     */
    vector<int> reOrderArray(vector<int>& array) {
        // write code here
        vector<int> ans(array.size(), 0);
        int pos=0;
        for(int i=0,j=0;i<array.size(); ++i){
            if(array[i]%2){
                ans[j++]=array[i];
            }
            pos=j;
        }
        for(int i=0,j=pos;i<array.size(); ++i){
            if(array[i]%2==0){
                ans[j++]=array[i];
            }
        }
        return ans;
    }
};

时间O(n^2) 空间O(1)

class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param array int整型vector 
     * @return int整型vector
     */
    vector<int> reOrderArray(vector<int>& array) {
        // write code here
        int i=0, j=0;//扫奇数,头插就可
        //j是奇数位置,i是奇数插入后面的一个位置
        while(j<array.size()){
            if(array[j]%2){
                int temp=array[j];
                for(int k=j; k>i;k--){
                //注意要从后往前,否则会覆盖住
                    array[k]=array[k-1];
                }
                array[i++]=temp;
            }
            j+=1;
        }
        return array;
    }
};

知识点

  • 位逻辑运算符:
    & (位 “与”) and
    ^ (位 “异或”)
    | (位 “或”) or
    ~ (位 “取反”)
    移位运算符:
    <<(左移)
    >>(右移)
    逻辑运算符:
    && || !

  • 一个整数,减去1后再和原来的数位与,相当于把最右边的1变成0

  • string.erase string.find_first_not_of
    参考一
    其他去空格
    str.erase(0, str.find_first_not_of(" “));
    str.erase(str.find_last_not_of(” ")+1);

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值