剑指offer46-50

求1+2+3+…+n的值

题目描述:求1+2+3+…+n,要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句(A?B:C)。
题目分析:这道题什么也不能用,那直接加法就完了,不能for就递归呗。不用if的话就利用与的特性就好了。
需利用逻辑与的短路特性实现递归终止。 2.当n==0时,(n>0)&&((sum+=Sum_Solution(n-1))>0)只执行前面的判断,为false,然后直接返回0;
3.当n>0时,执行sum+=Sum_Solution(n-1),实现递归计算Sum_Solution(n)。

class Solution {
public:
    int Sum_Solution(int n) {
        int ans = n;
        ans && (ans += Sum_Solution(n - 1));//当ans为0时就与为0,自动递归结束而不需要判断
        return ans;
    }
};

不用加减乘除做加法

题目描述:写一个函数,求两个整数之和,要求在函数体内不得使用+、-、*、/四则运算符号。
题目分析:
首先看十进制是如何做的: 5+7=12,三步走
第一步:相加各位的值,不算进位,得到2。
第二步:计算进位值,得到10. 如果这一步的进位值为0,那么第一步得到的值就是最终结果。
第三步:重复上述两步,只是相加的值变成上述两步的得到的结果2和10,得到12。

同样我们可以用三步走的方式计算二进制值相加: 5-101,7-111 第一步:相加各位的值,不算进位,得到010,二进制每位相加就相当于各位做异或操作,101^111。

第二步:计算进位值,得到1010,相当于各位做与操作得到101,再向左移一位得到1010,(101&111)<<1。

第三步重复上述两步, 各位相加 010^1010=1000,进位值为100=(010&1010)<<1。
继续重复上述两步:1000^100 = 1100,进位值为0,跳出循环,1100为最终结果。

class Solution {
public:
    int Add(int num1, int num2)
    {
        while(num2!=0){
            int temp=num1^num2;
            num2=(num1&num2)<<1;
            num1=temp;
        }
        return num1;
    }
};

把字符串转化为整数

题目描述:将一个字符串转换成一个整数,要求不能使用字符串转换整数的库函数。 数值为0或者字符串不是一个合法的数值则返回0
题目分析:很简单的题,没啥说的,情况考虑完就行了。数据上下 溢出,空字符串,只有正负号,有无正负号,错误标志输出

class Solution {
public:
    bool IsShuzi(char k) {
	    if (k >= '0' && k <= '9') {
		    return true;
	    }
	    else { return false; }
    }
    int StrToInt(string str) {
	    vector<int>temp;
	    int first = 0;
	    int flag = 1;
	    if (str[0] == '+' ) {
		    first = 1;
	    }
	    if (str[0] == '-') {
		    first = 1;
		    flag = -1;
	    }
    	for (int i = first; i < str.length(); i++) {
		    if (IsShuzi(str[i]) == 0) {
			    return 0;
		    }
		temp.push_back((int)(str[i] - '0'));
	    }
	    long output=0;
	    for (int i = 0; i < temp.size(); i++) {
            int pre=output;
		    output += temp[i] * pow(10,(temp.size() - i-1));
       
	    }
        if(output>0x7FFFFFFF && flag==1)return 0;
        if(output>0x80000000 && flag==-1)return 0;
	    return output*flag;
    }
};

数组中重复的数字

题目描述:在一个长度为n的数组里的所有数字都在0到n-1的范围内。 数组中某些数字是重复的,但不知道有几个数字是重复的。也不知道每个数字重复几次。请找出数组中任意一个重复的数字。 例如,如果输入长度为7的数组{2,3,1,0,2,5,3},那么对应的输出是第一个重复的数字2。
题目分析:简单利用map性质即可。

class Solution {
public:
	// Parameters:
	//        numbers:     an array of integers
	//        length:      the length of array numbers
	//        duplication: (Output) the duplicated number in the array number
	// Return value:       true if the input is valid, and there are some duplications in the array number
	//                     otherwise false
	bool duplicate(int numbers[], int length, int* duplication) {
		if (length == 0)return false;
		map<int,int>temp;
		for (int i = 0; i < length; i++) {
			temp[numbers[i]]++;
		}
		for (int i = 0; i < length; i++) {
			if (temp[numbers[i]] > 1) {
				*duplication = numbers[i];
				return true;
			}
		}
		return false;
	}
};

当然这个题有一个牛逼的方法,非常的简单而且不需要额外的空间。
题目里写了数组里数字的范围保证在0 ~ n-1 之间,所以可以利用现有数组设置标志,当一个数字被访问过后,可以设置对应位上的数 + n,之后再遇到相同的数时,会发现对应位上的数已经大于等于n了,那么直接返回这个数即可。

int find_dup( int numbers[], int length) {
    for ( int i= 0 ; i<length; i++) {
        int index = numbers[i];
        if (index >= length) {       //如果大于值,就恢复原本的值
            index -= length;
        }   
        if (numbers[index] >= length) {    //如果检测到原来的值发生了变化,那就说明出现了两次
            return index;
        }   
        numbers[index] = numbers[index] + length;    //给对应的位加n
    }   
    return - 1 ; 
}

构建乘积数组

题目描述:给定一个数组A[0,1,…,n-1],请构建一个数组B[0,1,…,n-1],其中B中的元素B[i]=A[0]A[1]…*A[i-1]A[i+1]…*A[n-1]。不能使用除法。
题目分析:B[i]的值可以看作下图的矩阵中每行的乘积。下三角用连乘可以很容求得,上三角,从下向上也是连乘。因此我们的思路就很清晰了,先算下三角中的连乘,即我们先算出B[i]中的一部分,然后倒过来按上三角中的分布规律,把另一部分也乘进去。
在这里插入图片描述

class Solution {
public:
	vector<int> multiply(const vector<int>& A) {
		int number = A.size();
		vector<int>output(number);
		vector<int>output1(number);
		int temp1=1;
		for (int i = 0; i < number; i++) {
			output1[i] = temp1;
			temp1 = temp1 * A[i];
		}
		vector<int>output2(number);
		int temp2 = 1;
		for (int i = number - 1; i >= 0; i--) {
			output2[i] = temp2;
			temp2 = temp2 * A[i];
		}
		for (int i = 0; i < number; i++) {
			output[i] = output1[i] * output2[i];
		}
		return output;

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值