力扣解题思路:脑筋急转弯系列

172. 阶乘后的零


思路:给定一个整数 n,返回 n! 结果尾数中零的数量。
我们知道,尾部的 0 由 2 * 5 得来,2 的数量明显多于 5 的数量,因为2永远先于5出现,因此只要统计有多少个 5 即可。
对于一个数 N,它所包含 5 的个数为:N/5 + N/5^2 + N/5^3 + …,其中 N/5 表示不大于 N 的数中 5 的倍数贡献一个 5,N/5^2 表示不大于 N 的数中 5^2 的倍数再贡献一个 5 …。

//首先题目的意思是末尾有几个0
// 比如6! = 【1* 2* 3* 4* 5* 6】
// 其中只有2*5末尾才有0,所以就可以抛去其他数据 专门看2 5 以及其倍数 毕竟 4 * 25末尾也是0
// 比如10! = 【2*4*5*6*8*10】
// 其中 4能拆成2*2  10能拆成2*5 
// 所以10! = 【2*(2*2)*5*(2*3)*(2*2*2)*(2*5)】
// 一个2和一个5配对 就产生一个0 所以10!末尾2个0
// 转头一想 2肯定比5多 所以只数5的个数就行了
// 假若N=31 31里能凑10的5为[5, 2*5, 3*5, 4*5, 25, 6*5] 其中 25还能拆为 5**2 
// 所以 里面的5的个数为 int(31/(5**1)) +  int(31/(5**2))
// 所以 只要先找个一个 5**x < n 的x的最大数 然后按上面循环加起来
public int trailingZeroes(int n) {
   
    return n == 0 ? 0 : n / 5 + trailingZeroes(n / 5);
}

如果统计的是 N! 的二进制表示中最低位 1 的位置,只要统计有多少个 2 即可 。和求解有多少个 5 一样,2 的个数为 N/2 + N/2^2 + N/2^3 + …

拓展:求n的阶乘最后一位非0数字?

453. 最小操作次数使数组元素相等


思路:给定一个长度为 n 的 非空 整数数组,每次操作将会使 n - 1 个元素增加 1。找出让数组所有元素相等的最小操作次数。

输入:
[1,2,3]
输出:
3
解释:
只需要3次操作(注意每次操作会增加两个元素的值):
[1,2,3]  =>  [2,3,3]  =>  [3,4,3]  =>  [4,4,4]

每次操作将会使 n - 1 个元素增加 1,相当于只使一个元素减一,因为只能做减法,所以是取最小值而不是中位数来逼近最终值

public int minMoves(int[] nums) {
   //因为只能做减法,所以是取最小值而不是中位数!
    int min = Integer.MAX_VALUE;
	for( int i = 0; i < nums.length; i++)
		if( min > nums[i]) min = nums[i];
	int result = 0;
	for( int i = 0; i < nums.length; i++)
		result += nums[i] - min;
	return result;
}

462. 最少移动次数使数组元素相等 II


思路:给定一个非空整数数组,找到使所有数组元素相等所需的最小移动数,其中每次移动可将选定的一个元素加1或减1。 您可以假设数组的长度最多为10000。

Input:
[1,2,3]

Output:
2

Explanation:
Only two moves are needed (remember each move increments or decrements one element):

[1,2,3]  =>  [2,2,3]  =>  [2,2,2]

我最开始想到的是用平均数,结果发现不对,参考别人的答案后发现应该使用中位数,随便举个例子如数组长度为奇数2n+1 则中位数两边各有n个数 设左边所有数和中位数的差值和为x 右边所有数和中位数的差值和为y 则所有需要移动的次数为x+y 如果不选择中位数 例如选择中位数-1 这样总的移动次数就变成了 >= ((x-n) + (y+n) + 1) 最好的情况下比中位数大1 如果数组长度是偶数 有两个中位数 选择两个中位数的任何一个或者两个中位数的平均数 都是可以的。

设 m 为中位数。a 和 b 是 m 两边的两个元素,且 b > a。要使 a 和 b 相等,它们总共移动的次数为 b - a,这个值等于 (b - m) + (m - a),也就是把这两个数移动到中位数的移动次数。

public int minMoves2(int[] nums) {
   
    Arrays.sort(nums);
    int move = 0;
    int l = 0, h = nums.length - 1;
    while (l <= h) {
   
        move += nums[h] - nums[l];
        l++;
        h--;
    }
    return move;
}

326. 3的幂


思路:给定一个整数,写一个函数来判断它是否是 3 的幂次方。
这一题比较简单,先用最规矩的方法,不断地除以3,最后为1则一定是3的幂次方:

public boolean isPowerOfThree(int n) {
   
    if (n == 0) {
   
        return false;
    }
    while (n % 3 == 0) {
   
        n /= 3;
    }
    return n == 1;
}

另外还有一种比较巧妙的方法,因为3的幂次的质因子只有3,而所给出的n如果也是3的幂次,故而题目中所给整数范围内最大的3的幂次的因子只能是3的幂次,1162261467是3的19次幂,是整数范围内最大的3的幂次:

public boolean isPowerOfThree(int n) {
   
    return n > 0 && (1162261467 % n == 0);
}

342. 4的幂


思路:判断一个数是不是4的幂,首先还是一样需要找规律,4的幂一定是2的幂,那么也是只有一个位上有1,可以通过去掉一个1后是否为0即(num & (num - 1)) == 0来判断是否满足这个条件。另外,1必须在奇数位上(第0位算作第1位),不然还是2的幂,我们可以将这个数和…1010101010相与如果为0则是满足的。当然这个数还得大于0。

public boolean isPowerOfFour(int num) {
   
    return (num > 0) && ((num & (num - 1)) == 0) && ((num & 0xaaaaaaaa) == 0);//check(is or not) a power of 2.
}

nowCoder:求 1+2+3+...+n


思路:题目要求不能使用乘除法、for、while、if、else、switch、case 等关键字及条件判断语句 A ? B : C。
常规方法是不断调用递归函数累加,但是无论如何递归的出口还是需要if判断的,所以还有什么别的方式吗?

!!!!我们可以联想到&&的短路特性即在第一个条件语句为 false 的情况下不会去执行第二个条件语句。

利用这一特性,将递归的返回条件取非然后作为 && 的第一个条件语句,递归的主体转换为第二个条件语句,那么当递归的返回条件为 true 的情况下就不会执行递归的主体部分,递归返回。
本题的递归返回条件为 n <= 0,取非后就是 n > 0;递归的主体部分为 sum += Sum_Solution(n - 1),转换为条件语句后就是 (sum += Sum_Solution(n - 1)) > 0。

public int Sum_Solution(int n) {
   
    int sum = n;
    boolean b = (n > 0) && ((sum += Sum_Solution(n - 1)) > 0);
    return sum;
}

nowCoder:不用加减乘除做加法


思路:要求不得使用 +、-、*、/ 四则运算符号,那么我们就可以使用位运算。a ^ b 表示没有考虑进位的情况下两数的和,(a & b) << 1 就是进位。递归会终止的原因是 (a & b) << 1 最右边会多一个 0,那么继续递归,进位最右边的 0 会慢慢增多,最后进位会变为 0,递归终止。

public int Add(int a, int b) {
   
    return b == 0 ? a : Add(a ^ b, (a & b) << 1);
}

面试题 08.05. 递归乘法


思路:递归乘法。 写一个递归函数,不使用 * 运算符, 实现两个正整数的相乘。可以使用加号、减号、位移,但要吝啬一些。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值