剑指Offer题解(一)数字问题

剑指Offer比较适合校招同学练手,校招过程中也临时抱佛脚刷了这60多道题,开此博客谨为记录下个人粗浅的题解(均为C++版)。

数字问题中有很多小trick,一般是从二进制和位运算的角度入手。

    #include
    using namespace std;
    
    #pragma region 二进制中1的个数 二进制
    //输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。
    #pragma endregion
    
    class Solution {
    public:
    	int NumberOf1(int n) {
    		int sum = 0;
    		unsigned int flag = 1;
    		for (int i = 0; i < 32; i++)
    		{
    			if (n & flag)
    				sum++;
    			flag = flag << 1;
    		}
    		return sum;
    	}
    };


    #pragma region 求1+2+3+...+n
    //求1+2+3+...+n,要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句(A?B:C)。
    #pragma endregion
    
    class Temp {
    public:
    	static int Sum;
    	static int N;
    	Temp()
    	{
    		++N;
    		Sum += N;
    	}
    	static int GetSum() {
    		return Sum;
    	}
    	static void Reset()
    	{
    		Sum = 0;
    		N = 0;
    	}
    };
    int Temp::Sum = 0;
    int Temp::N = 0;
    
    class Solution {
    public:
    	friend class Temp;
    	int Sum_Solution(int n) {
    		Temp::Reset();
    		Temp *t = new Temp[n];
    		delete[]t;
    		t = nullptr;
    		return Temp::GetSum();
    	}
    };
    
    
    #pragma region 不用加减乘除做加法 ^ 异或
    //写一个函数,求两个整数之和,要求在函数体内不得使用+、-、*、/四则运算符号。
    
    #pragma endregion
    
    class Solution {
    public:
    	int Add(int num1, int num2)
    	{
    		while (num1 & num2)
    		{
    			int temNum1 = num1 ^ num2;
    			num2 = (num1 & num2) << 1;
    			num1 = temNum1;
    		}
    		return num1 | num2;
    	}
    };
    
    
    
    #pragma region 数值的整数次方 
    //给定一个double类型的浮点数base和int类型的整数exponent。求base的exponent次方。
    #pragma endregion
    
    class Solution {
    public:
    	double Power(double base, int exponent) {
    		if (base == 0 && exponent <= 0)
    			return 0;
    		else if (exponent < 0)
    		{
    			unsigned int absExponent = (unsigned int)(-exponent);
    			return 1.0 / PowerUnsigned(base, absExponent);
    		}
    		return PowerUnsigned(base, exponent);
    	}
    	double PowerUnsigned(double unsignedBase, int exponent)
    	{
    		if (exponent == 0)
    			return 1;
    		else if (exponent == 1)
    			return unsignedBase;
    		double result = PowerUnsigned(unsignedBase, exponent >> 1);
    		result *= result;
    		if (exponent & 0x1)
    			result *= unsignedBase;
    		return result;
    	}
    };
    
    
    
    #pragma region 整数中1出现的次数 
    //求出1~13的整数中1出现的次数, 并算出100~1300的整数中1出现的次数?
    //为此他特别数了一下1~13中包含1的数字有1、10、11、12、13因此共出现6次, 但是对于后面问题他就没辙了。
    //ACMer希望你们帮帮他, 并把问题更加普遍化, 可以很快的求出任意非负整数区间中1出现的次数(从1 到 n 中1出现的次数)。
    #pragma endregion
    
    class Solution {
    public:
    	int NumberOf1Between1AndN_Solution(int n)
    	{
    		if (n < 1)
    			return 0;
    		//12045
    		int divisor = 10;
    		int remainder = 0;
    		vector<int> numOfOneInTenPower;
    		vector<int> numOfDigit;
    		vector<int> numOfRemainder;
    		numOfOneInTenPower.push_back(1);
    		int nCopy = n;
    		int digitNumber = 0;
    		while (nCopy > 0) // 5次
    		{
    			//余数 5 45 045 2045 12045
    			remainder = n % divisor;
    			numOfRemainder.push_back(remainder);
    			//每一位 5 4 0 2 1
    			digitNumber = nCopy % 10;
    			numOfDigit.push_back(digitNumber);
    			nCopy /= 10;
    
    			// 1 20 300 xxxx xxxxx xxxxx
    			numOfOneInTenPower.push_back(numOfOneInTenPower[numOfOneInTenPower.size() - 1] * 10 + divisor);
    			divisor *= 10;
    		}
    		int ret = 0;
    		int powerOften = 10;
    		if (numOfDigit[0] > 0)
    			++ret;
    		for (int i = 1; i < numOfDigit.size(); ++i)
    		{
    			if (numOfDigit[i] > 1)
    			{
    				ret += numOfDigit[i] * numOfOneInTenPower[i - 1] + powerOften;
    			}
    			else if (numOfDigit[i] == 1)
    			{
    				ret += numOfOneInTenPower[i - 1] + numOfRemainder[i - 1] + 1;
    			}
    			powerOften *= 10;
    		}
    		return ret;
    	}
    };
    
    
    #pragma region 丑数 数组 自上而下 自下而上
    //把只包含质因子2、3和5的数称作丑数(Ugly Number)。
    //例如6、8都是丑数,但14不是,因为它包含质因子7。 
    //习惯上我们把1当做是第一个丑数。求按从小到大的顺序的第N个丑数。
    #pragma endregion
    
    class Solution {
    public:
    	int GetUglyNumber_Solution(int index) {
    		if (index < 1)
    			return 0;
    		vector<int> vec;
    		vec.push_back(1);
    		int index2, index3, index5;
    		index2 = index3 = index5 = 0;
    		for (int i = 0; i < index - 1; i++)
    		{
    			int vecNext2 = vec[index2] * 2;
    			int vecNext3 = vec[index3] * 3;
    			int vecNext5 = vec[index5] * 5;
    			int next = vecNext2 < vecNext3 ? vecNext2 : vecNext3;
    			next = next < vecNext5 ? next : vecNext5;
    			vec.push_back(next);
    			while (vec[index2] * 2 <= vec[vec.size() - 1])
    				index2++;
    			while (vec[index3] * 3 <= vec[vec.size() - 1])
    				index3++;
    			while (vec[index5] * 5 <= vec[vec.size() - 1])
    				index5++;
    
    		}
    		return vec[index - 1];
    	}
    };
    
    
    #pragma region 只出现一次的数  
    //两个数只出现了一次 找出来
    #pragma endregion
    
    class Solution {
    public:
    	void FindNumsAppearOnce(vector<int> data, int* num1, int *num2) {
    		int xor_one = 0;
    		for (int i = 0; i < data.size(); i++)
    		{
    			xor_one = xor_one ^ data[i];
    		}
    		unsigned int flag = 1;
    		while (!(xor_one & flag))
    		{
    			flag = flag << 1;
    		}
    		vector<int> data_partOne;
    		vector<int> data_partTwo;
    		for (int i = 0; i < data.size(); i++)
    		{
    			if (flag & data[i])
    				data_partOne.push_back(data[i]);
    			else
    				data_partTwo.push_back(data[i]);
    		}
    		for (int i = 0; i < data_partOne.size(); i++)
    		{
    			*num1 = *num1 ^ data_partOne[i];
    		}
    		for (int i = 0; i < data_partTwo.size(); i++)
    		{
    			*num2 = *num2 ^ data_partTwo[i];
    		}
    	}
    };

你可能感兴趣的:(剑指Offer,算法,C++)