leetcode - cn | 数学&位运算

只出现一次的数字

给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。

说明:

你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?

示例 1:

输入: [2,2,1]
输出: 1

示例 2:

输入: [4,1,2,1,2]
输出: 4

使用位运算符实现

| 或 只要有一个1就是1,全为0为0

& 与 只要有一个为0就是0,全为1为1

^ 异或 相同为0,相异为1

class Solution {
    public int singleNumber(int[] nums) {
        //利用数据结构set的性质进行
        // Set<Integer> set = new HashSet<Integer>();
        // for(int i=0;i<nums.length;i++){
        //     if(set.add(nums[i]))
        //         set.add(nums[i]);
        //     else
        //         set.remove(nums[i]);
        // }
        // Iterator<Integer> it = set.iterator();
        // return it.next();
        
        
        //位运算
        int flag = 0;
        for(int i = 0;i<nums.length;i++){
            flag=flag^nums[i];
        }
        return flag;
    }
}

直线上最多的点数

给定一个二维平面,平面上有 个点,求最多有多少个点在同一条直线上。

示例 1:

输入: [[1,1],[2,2],[3,3]]
输出: 3
解释:
^
|
|        o
|     o
|  o  
+------------->
0  1  2  3  4

示例 2:

输入: [[1,1],[3,2],[5,3],[4,1],[2,3],[1,4]]
输出: 4
解释:
^
|
|  o
|     o        o
|        o
|  o        o
+------------------->
0  1  2  3  4  5  6

这道题太难了吧,如果有重复的点的话,要考虑的情况就太多了

也可能是自己思路不对

//会有重复的点出现的可能,没有说明重复就默认重复
class Solution {
public:
    int maxPoints(vector<vector<int>>& points) {
        int size=points.size();
        if(size<=2)
            return size;
        int maxx=2;
        long long a,b,c;
        int temp;
        for(int i=0;i<points.size();i++){
            int count=1;
            int equal=1;
            for(int j=i+1;j<points.size();j++){
                count++;
                if(points[i][0]==points[j][0]&&points[i][1]==points[j][1]){
                    maxx=max(count,maxx);
                    equal++;
                    continue;
                }
                a=points[i][1]-points[j][1];
                b=points[j][0]-points[i][0];
                c=-a*points[i][0]-b*points[i][1];
                for(int k=j+1;k<points.size();k++){
                    if(points[k][0]==points[i][0]&&points[k][1]==points[i][1])
                        count++;
                    else if(points[k][0]==points[j][0]&&points[k][1]==points[j][1])
                        count++;
                    else if(a*points[k][0]+b*points[k][1]+c==0){
                        count++;
                    }
                        
                }
                maxx=max(count,maxx);
                count=equal;
            }
        }
        return maxx;
    }
};

判断三个点是否在同一条直线上,求出两个点的表达式 ax+by+c=0,即a,b,c的值,看第三个点是否符合。

这道题的关键在于要把重复的点也算上

似乎不用搞得这么复杂,在最开始的时候对数据进行一下处理,合并相同的数据似乎就可以,时间也不会太超时吧


分数到小数

给定两个整数,分别表示分数的分子 numerator 和分母 denominator,以字符串形式返回小数。

如果小数部分为循环小数,则将循环的部分括在括号内。

示例 1:

输入: numerator = 1, denominator = 2
输出: "0.5"

示例 2:

输入: numerator = 2, denominator = 1
输出: "2"

示例 3:

输入: numerator = 2, denominator = 3
输出: "0.(6)"

是一道简单的算术题目,全程按照手算除法的过程实现。

唯一困难的地方是如何判断循环小数,从手动计算除法的过程可以得知如果出现了重复的余数,最初的想法是把每一次运算的余数存下来,之后再继续检测,但是这样存在问题,如果本次运算的余数在之前已经出现过不代表本次运算的商重复出现,而是代表下次运算的商重复出现。所以最后改为在存储本次运算的除数,在运算之前检查除数是否出现过。

另外还有很多细节需要考虑:

0/1=0

0/-1=0

1/6=0.1(6)

7/12=0.58(3)

-1/-2147483648  可能会越界

1/-2=0.5

class Solution {
public:
    int circu(int rmd,vector<string> &yushu){  //判断是否出现了相同的余数,返回相同值得下标
        string s=to_string(rmd);
        for(int i=0;i<yushu.size();i++){
            if(yushu[i]==s)
                return i;
        }
        return -1;
    }
    
    string fractionToDecimal(int numerator, int denominator) {
        //出现相同的余数就代表循环小数开始了
        if(numerator==0)
            return "0";
        vector<string> shang;
        vector<string> yushu;
        string res;
        
        long long numerator2;
        long long denominator2;
        long long quo;  //商
        long long rmd;  //余数
        int fu=0;
        if(numerator<0){
            fu=fu^1;
            numerator2=numerator;
            numerator2=-numerator2;
        }
        else{
            numerator2=numerator;
        }
        if(denominator<0){
            fu=fu^1;
            denominator2=denominator;
            denominator2=-denominator2;
        }
        else{
            denominator2=denominator;
        }
        if(fu==1) res.push_back('-');
        
        quo=numerator2/denominator2;
        rmd=numerator2%denominator2;
        if(rmd==0){  //如果能被整除
            res+=to_string(quo);
            return res;
        }
        else{  //如果不能被整除
            res+=to_string(quo);
            res.push_back('.');
            numerator2=rmd*10;
            quo=numerator2/denominator2;
            rmd=numerator2%denominator2;
            while(rmd!=0&&circu(numerator2,yushu)==-1){//当没有除尽且还没有出现重复得余数时
                yushu.push_back(to_string(numerator2));
                shang.push_back(to_string(quo));
                numerator2=rmd*10;
                quo=numerator2/denominator2;
                rmd=numerator2%denominator2;
            }
            if(rmd==0){
                shang.push_back(to_string(quo));
                for(int i=0;i<shang.size();i++){
                    res+=shang[i];
                }
                return res;
            }
            else if(circu(numerator2,yushu)!=-1){
                int bi=circu(numerator2,yushu);
                for(int i=0;i<bi;i++){
                    res+=shang[i];
                }
                res.push_back('(');
                for(int i=bi;i<shang.size();i++)
                    res+=shang[i];
                res.push_back(')');
            }
            return res;
        }
        
    }
};

阶乘后的零

给定一个整数 n,返回 n! 结果尾数中零的数量。

示例 1:

输入: 3
输出: 0
解释: 3! = 6, 尾数中没有零。

示例 2:

输入: 5
输出: 1
解释: 5! = 120, 尾数中有 1 个零.

说明: 你算法的时间复杂度应为 O(log n) 

由于任何一个正整数都可以拆分成素数的乘积,将10000以内的素数打印出来发现除了2和5之外的其他素数均以3,7,9,1等数结尾,而看末尾的0的个数实际上就是看能够乘出来多少个10。故将题目转化为n!分解素因数。

假设素数为q,n!由1-n的乘积得到,可以贡献出一个q的数的个数为 n/q,同理,可以再贡献出一个q(也就是一共贡献出2个q)的数的个数为n/q^2;将n/q+n/q^2+n/q^3……相加则可以得到n!中q的个数。

class Solution {
public:
    int trailingZeroes(int n) {
        int two=0;
        int five=0;
        for(long long i=2;i<=n;i=i*2){
            two=two+n/i;
        }
        for(long long i=5;i<=n;i=i*5){
            five=five+n/i;
        }
        return min(two,five);
    }
};

颠倒二进制位

颠倒给定的 32 位无符号整数的二进制位。

 

示例 1:

输入: 00000010100101000001111010011100
输出: 00111001011110000010100101000000
解释: 输入的二进制串 00000010100101000001111010011100 表示无符号整数 43261596      因此返回 964176192,其二进制表示形式为 00111001011110000010100101000000

示例 2:

输入:11111111111111111111111111111101
输出:10111111111111111111111111111111
解释:输入的二进制串 11111111111111111111111111111101 表示无符号整数 4294967293,
      因此返回 3221225471 其二进制表示形式为 10101111110010110010011101101001。
class Solution {
public:
    uint32_t reverseBits(uint32_t n) {
        //这个太巧妙了吧
        uint32_t ans=0;
        //进制的本质
        int i=32;
        while(i--)
        {
            ans<<=1;
            ans+=n&1;
            n>>=1;
        }
        return ans;
    }
};

看的别人的答案,太巧妙了吧


位1的个数

编写一个函数,输入是一个无符号整数,返回其二进制表达式中数字位数为 ‘1’ 的个数(也被称为汉明重量)。

 

示例 1:

输入:00000000000000000000000000001011
输出:3
解释:输入的二进制串 00000000000000000000000000001011 中,共有三位为 '1'。

示例 2:

输入:00000000000000000000000010000000
输出:1
解释:输入的二进制串 00000000000000000000000010000000 中,共有一位为 '1'。

示例 3:

输入:11111111111111111111111111111101
输出:31
解释:输入的二进制串 11111111111111111111111111111101 中,共有 31 位为 '1'。

 

提示:

  • 请注意,在某些语言(如 Java)中,没有无符号整数类型。在这种情况下,输入和输出都将被指定为有符号整数类型,并且不应影响您的实现,因为无论整数是有符号的还是无符号的,其内部的二进制表示形式都是相同的。
  • 在 Java 中,编译器使用二进制补码记法来表示有符号整数。因此,在上面的 示例 3 中,输入表示有符号整数 -3

 

进阶:
如果多次调用这个函数,你将如何优化你的算法?

class Solution {
public:
    int hammingWeight(uint32_t n) {
        int ans=0;
        int i=32;
        while(i--){
            if(n&1==1)
                ans++;
            n=n>>1;
        }
        return ans;
    }
};

计算质数

统计所有小于非负整数 的质数的数量。

示例:

输入: 10
输出: 4
解释: 小于 10 的质数一共有 4 个, 它们是 2, 3, 5, 7 。

素数筛法

class Solution {
public:
    int countPrimes(int n) {
        if(n<2) return 0;
        vector<bool> prime(n,true);
        prime[0]=false;
        prime[1]=false;
        int count=0;
        for(int i=2;i<n;i++){
            if(prime[i]==true){
                count++;
                for(int j=2;i*j<n;j++){
                    prime[i*j]=false;
                }
            }
        }
        return count;
    }
};

缺失数字

给定一个包含 0, 1, 2, ..., n 中 n 个数的序列,找出 0 .. n 中没有出现在序列中的那个数。

示例 1:

输入: [3,0,1]
输出: 2

示例 2:

输入: [9,6,4,2,3,5,7,0,1]
输出: 8

说明:
你的算法应具有线性时间复杂度。你能否仅使用额外常数空间来实现?

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

3的幂

给定一个整数,写一个函数来判断它是否是 3 的幂次方。

示例 1:

输入: 27
输出: true

示例 2:

输入: 0
输出: false

示例 3:

输入: 9
输出: true

示例 4:

输入: 45
输出: false

进阶:
你能不使用循环或者递归来完成本题吗?

解法

  1. 直接继续除
  2. 穷举
  3. 使用int中最大的3的幂次值除当前值看是否有余数

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值