剑指offer ====数学计算(二进制1的个数、数值整数次方、1-n的和、1出现的次数、Fibonacci)

1. 二进制中1的个数

题目描述

输入一个整数,输出该数32位二进制表示中1的个数。其中负数用补码表示。

https://www.nowcoder.com/practice/8ee967e43c2c4ec193b040ea7fbb10b8?tpId=13&&tqId=11164&rp=1&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking

题目分析

当一个数减去1 那个这个数最右边的1之后的0将会变成1,最右边的1左边不变,然后这个数和这个数-1进行与运算,那么这个数最右边的1将会0 循环此过程 直到这个数全部变为0;
ex: 10的二进制是 1010 10-1的二进制是1001 相与结果为1000 10这个数最右边的1变为o 以此类推最终10会变为0

C++代码

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

2. 数值的整数次方

题目描述

给定一个double类型的浮点数base和int类型的整数exponent。求base的exponent次方。

保证base和exponent不同时为0

https://www.nowcoder.com/practice/1a834e5e3e1a4b7ba251417554e07c00?tpId=13&&tqId=11165&rp=1&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking

题目分析

暴力法

很显然就是n个b相乘。循环n次。

C++代码

class Solution {
public:
    double Power(double base, int exponent) {
        if(exponent < 0)
        {
            base = 1 / base;
            exponent = -exponent;
        }
        double ret = 1.0;
        for(int i =0; i< exponent; i++)
        {
            ret *= base;
        }
        return ret;
    
    }
};

3. 求1-n的和

题目描述

求1+2+3+…+n,要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句(A?B:C)。

https://www.nowcoder.com/practice/7a0da8fc483247ff8800059e12d7caf1?tpId=13&&tqId=11200&rp=1&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking

题目分析

  1. 可知求和公式,
    这种方法不行,因为需要用到乘法

  2. 逻辑与&&连接符。
    A&&B,表示如果A成立则执行B,否则如果A不成立,不用执行B
    因此我们可以这样。在n>0的时候,执行递归函数。

C++代码

class Solution {
public:
    int Sum_Solution(int n) {
        return n*(n+1) / 2;
    }
};
class Solution {
public:
    int Sum_Solution(int n) {
        int sum = n;
        sum && (sum += Sum_Solution(n-1));
        return sum;  
    }
};

4. 整数中1出现的次数

题目描述

求出113的整数中1出现的次数,并算出1001300的整数中1出现的次数?为此他特别数了一下1~13中包含1的数字有1、10、11、12、13因此共出现6次,但是对于后面问题他就没辙了。ACMer希望你们帮帮他,并把问题更加普遍化,可以很快的求出任意非负整数区间中1出现的次数(从1 到 n 中1出现的次数)。

https://www.nowcoder.com/practice/bd7f978302044eee894445e244c7eee6?tpId=13&&tqId=11184&rp=1&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking

题目分析

需要通过找规律来分析。
假设我们对5014这个数字求解。
(1)个位上1出现的个数:记高位为high=501,当前位为cur=4。
那么高位从0~500变化的过程中,每一个变化中1只出现1次,即(高位1)这样的数字;
高位是501时,因为当前位是4,所以1只能出现一次,即5011。
所以总共出现的次数为high*1+1=502。

(2)十位1出现的个数:记高位high=50,当前位为cur=1,低位为low=4。
那么高位从0~ 49变化的过程中,每一个变化中1出现10次,即(高位10)~(高位19)这样的数字;
高位为50的时候,因为当前位是1,所以我们要看低位来决定出现的次数,因为低位为4,所以此时出现5次,即5010~5014这样的数字。
所以总共出现的次数为high*10+4=504。

(3)百位1出现的个数:记高位high=5,当前位cur=0,低位为low=14。
那么高位从0~ 4的过程中,每一个变化1出现100次,即(高位100)~(高位199)这样的数字;
高位为5的时候,因为当前位为0,所以不存在出现1的可能性。
所以总共出现的次数为high*100+0=500。

(4)千位1出现的次数:记高位high=0,当前位cur=5,低位low=014。
那么因为没有高位所以直接看当前位,因为当前位为5,所以1出现的次数为1000,即1000~1999这样的数字。
所以总共出现的次数为high*1000+1000=1000。
综上,最终的结果将每个位置出现1的次数累加即可。

结论
我们假设高位为high,当前位为cur,低位为low,i代表着需要统计的位置数(1对应个位,10对应十位,100对应百位),则对每一位的个数count有:
cur=0,count = highi;
cur=1,count=high
i+low+1;
cur>1,count=high*i+i
最终累加所有位置上的个数即最终答案。

作者:lu-yang-shan-yu
链接:https://leetcode-cn.com/problems/1nzheng-shu-zhong-1chu-xian-de-ci-shu-lcof/solution/c-cong-ge-wei-bian-li-dao-zui-gao-wei-yi-ci-qiu-ji/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

C++代码

class Solution {
public:
    int NumberOf1Between1AndN_Solution(int n)
    {
        long i = 1;
        int count = 0;
        while((n/i)!= 0)
        {
            long cur = (n/i)%10;
            long high = n/(10*i);
            long low = n - (n/i)*i;
            if(cur == 0)
            {
                count += high * i;
            }else if(cur == 1)
            {
                count += high * i + low + 1; 
            }else{
                count += high * i + i;
            }
            i *= 10;
            
        }
        return count;
    
    }
};

5. Fibonacci数列

题目描述

因此,Fibonacci数列就形如:0, 1, 1, 2, 3, 5, 8, 13, …,在Fibonacci数列中的数我们称为Fibonacci数。给你一个N,你想让其变为一个Fibonacci数,每一步你可以把当前数字X变为X-1或者X+1,现在给你一个数N求最少需要多少步可以变为Fibonacci数。

https://www.nowcoder.com/practice/18ecd0ecf5ef4fe9ba3f17f8d00d2d66?tpId=85&&tqId=29846&rp=1&ru=/activity/oj&qru=/ta/2017test/question-ranking

题目分析

本题可以通过先找到距离N最近的两个Fibonacci数,这两个数分别取自距离N的最近的左边一个数L和右边一
个数R,然后通过min(N - L, R - N)找到最小步数。

C++代码


#include<iostream>
using namespace std;
int main()
{
    int N ,f, l,r,f0 = 0, f1 = 1;
    cin >> N;
    while(1)
    {
        f = f0 + f1;
        f0 = f1;
        f1 = f;
        if(f < N)
        {
            l = N - f;
        }
        else{
            r = f - N;
            break;
        }
    }
    cout << min(l,r) << endl;
    return 0;
}

©️2020 CSDN 皮肤主题: 1024 设计师:上身试试 返回首页