2018年力扣高频算法面试题1数学&位运算

友链

在这里插入图片描述

在这里插入图片描述

1、只出现一次的数字

给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。
要求:线性时间复杂度、不使用额外空间
解答:典型的位运算,相同的两个数异或为0,扩展形式为,找出给定非空整数数组中只出现一次的两个整数。

int singleNumber(vector<int>& nums) {
        int ans=nums[0];
        for(int i=1;i<nums.size();i++)
        {
            ans^=nums[i];
        }
        return ans;
    }

2、直线上最多的点数【需二刷】

参考

给定一个二维平面,平面上有 n 个点,求最多有多少个点在同一条直线上。
特殊情况:①是当两个点重合时,无法确定一条直线,但这也是共线的情况,需要特殊处理。②是斜率不存在的情况,由于两个点 (x1, y1) 和 (x2, y2) 的斜率k表示为 (y2 - y1) / (x2 - x1),那么当 x1 = x2 时斜率不存在,这种共线情况需要特殊处理。
哈希表:记录斜率和共线点个数之间的映射,其中第一种重合点的情况我们假定其斜率为 INT_MIN,第二种情况我们假定其斜率为 INT_MAX,这样都可以用 map 映射了。

class Solution {
public:
    int maxPoints(vector<vector<int>>& points) {
        int res = 0;
        for (int i = 0; i < points.size(); ++i) {
            int duplicate = 1;
            for (int j = i + 1; j < points.size(); ++j) {
                int cnt = 0;
                long long x1 = points[i][0], y1 = points[i][1];
                long long x2 = points[j][0], y2 = points[j][1];
                if (x1 == x2 && y1 == y2) {++duplicate; continue;}
                for (int k = 0; k < points.size(); ++k) {
                    int x3 = points[k][0], y3 = points[k][1];
                    if (x1 * y2 + x2 * y3 + x3 * y1 - x3 * y2 - x2 * y1 - x1 * y3 == 0) {
                        ++cnt;
                    }
                }
                res = max(res, cnt);
            }
            res = max(res, duplicate);
        }
        return res;
    }
};

3、分数到小数【需二刷】

参考

给定两个整数,分别表示分数的分子 numerator 和分母 denominator,以字符串形式返回小数。如果小数部分为循环小数,则将循环的部分括在括号内。
①循环体出现的标志是什么?我们研究一下1/6。
最开始补零,变成10/6,写成0.1,这时候余数是4。
余数4再去除以6,变成40/6,写成0.16,这时候余数是4,。
余数4再去除以6……
这个时候我们都知道接下来必定是循环体结构了,因为出现了相同的被除数。
所以我们不能把两个整数变成double类型,直接相除,而是应该不断地整数相除,记录余数,余数再去除以除数。
在这个过程中记录余数,如果出现了重复的余数,那么必定是循环体结构了。
②边界条件,比如-2147483648/-1,-1/-2147483648,7/-12等等。

string fractionToDecimal(int numerator, int denominator) 
    {
        if(numerator==INT_MIN&&denominator==-1)//边界条件,没法直接除,因为除完结果溢出
        return "2147483648";
        if(numerator==-1&&denominator==INT_MIN)//边界条件,都是int类型,没法除
        return "0.0000000004656612873077392578125";
        int shang=numerator/denominator,yushu=numerator%denominator;//记录商和余数
        string res;//最终要返回的string
        if(double(numerator)/double(denominator)<0)//如果两个数一正一负
        {
            if(shang==0)//如果商为0
                res='-'+to_string(abs(shang));//可能有的同学疑惑为什么要这样处理,比如7/-12,除完shang为0,但是我们要的是-0
            else
                res=to_string(shang);//如果不为0,那么直接处理
        }
        else//如果都是正数或者都是负数
            res=to_string(shang);//直接处理
        if(yushu==0)//如果余数为0,那么到此为止,返回res就可以了
            return res;
        res+='.';//如果还有余数,那么要加个小数点
        unordered_map<int,int>record;//记录出现过的余数和余数除以除数得到的商的位置
        while(yushu!=0)
        {
            yushu=abs(yushu);//余数有可能是负的,全都转为正数
            denominator=abs(denominator);//除数也转为正数
            yushu*=10;//余数乘10,作为新的被除数
            if(record.count(yushu))//如果之前出现过了这个余数,那么可以取出循环体了
            {
                int start=record[yushu],end=res.size()-1;//start和end表示循环体的开端和末尾
                res=res.substr(0,start)+'('+res.substr(start,end-start+1)+')';//加一下括号
                return res;//直接返回
            }
            record[yushu]=res.size();//如果没出现过,那么记录在record中,value是这个余数除以除数得到的商应该放的位置
            shang=yushu/denominator;//更新商
            yushu=yushu%denominator;//更新余数
            res+=to_string(shang);//加入最新的商
        }
        return res;//如果一直没有出现重复的余数,那么最终跳出循环后直接返回res
    }

4、阶乘后的零

给定一个整数 n,返回 n! 结果尾数中零的数量。
要求:时间复杂度应为 O(log n)。
思路:1~n之间有多少5的倍数。

class Solution {
public:
    int trailingZeroes(int n) {
        int res = 0;
        while(n){
            n /= 5;
            res += n;
        }
        return res;
    }
};

5、缺失数字

给定一个包含 0, 1, 2, …, n 中 n 个数的序列,找出 0 … n 中没有出现在序列中的那个数。
要求:算法应具有线性时间复杂度,仅使用额外常数空间来实现。
不缺失数字时候的和可以计算,缺失数字之后的和遍历一遍也可以计算出来,二者相减就是缺失的数字.

class Solution {
public:
    int missingNumber(vector<int>& nums) {
        int res=nums.size();
        for(int i=0;i<nums.size();i++)
        {
            res +=(i-nums[i]);
        }
        return res;
    }
};

6、3的幂

给定一个整数,写一个函数来判断它是否是 3 的幂次方。
进阶:你能不使用循环或者递归来完成本题吗?

class Solution {
public:
    bool isPowerOfThree(int n) {
        if(n == 0) return false;
        while(n%3 == 0) n /= 3;
        if(n == 1) return true;
        return false;
    }
};

7、颠倒二进制位【需二刷】

颠倒给定的 32 位无符号整数的二进制位。
进阶:如果多次调用这个函数,你将如何优化你的算法?

class Solution {
public:
    uint32_t reverseBits(uint32_t n) {
        uint32_t res = 0;
        for (int i = 0; i < 32; ++i) {
            if (n & 1 == 1) {  // 最后一位为1
                res = (res << 1) + 1;
            } else {
                res = res << 1;
            }
            n = n >> 1;
        }
        return res;
    }
};

补充题目

Sum of Two Integers

Calculate the sum of two integers a and b, but you are not allowed to use the operator + and -.
由于异或是相同则位0,不同则位1,因此我们可以把异或看成是一种不进位的加减法
由于与是全部位1则位1,否则位0,因此我们可以求与之后左移一位来表示进位

class Solution {
public:
    int getSum(int a, int b) {
        long long carry; // 64-bit
        while (b != 0) {
            carry = a & b;
            a = a ^ b;
            b = ((carry & 0xffffffff) << 1); // limited to 32 bits
        }
        return a;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值