递归&分治?我直接刷爆

本文介绍了使用递归和分治策略解决计算x的n次幂(Pow(x,n))以及寻找数组中多数元素的问题。提供了C++、Java和Python的AC代码实现,包括快速幂优化方法。同时,讨论了在处理负指数和数组边界值时的注意事项。
摘要由CSDN通过智能技术生成

csdn

递归&分治(Recursion&Partition)

数据结构简介…


高频面试题

1.Pow(x, n)

🚀题目链接:LeetCode50.Pow(x, n)

题目:

实现 pow(x, n) ,即计算 x 的整数 n 次幂函数(即, x n x^n xn )。

示例 1:

输入:x = 2.00000, n = 10
输出:1024.00000

示例 2:

输入:x = 2.10000, n = 3
输出:9.26100

示例 3:

输入:x = 2.00000, n = -2
输出:0.25000
解释:2-2 = 1/22 = 1/4 = 0.25

💯解法一:递归+分治思想

🍬C++ AC代码:

class Solution {
public:
    double myPow(double x, long long n) {
        if (n == 0)
            return 1.0;
        if (n < 0)
            return 1.0 / myPow(x, -n);
        if (n % 2 == 1)
            return x * myPow(x, n - 1);
        return myPow(x * x, n >> 1);
    }
};

Tips:

  • n<0时可以先取-n当作正数计算,在递归调用都结束后再取倒数。
  • ⭐力扣的初始代码模板myPow(double x, int n)中的n是int类型,这里改成了long long类型。因为存在一组测试用例1.00000,-2147483648n刚好是负数的边界值,再将n变成正数会比int型最大值多1。

Java AC代码:

class Solution {
    public double myPow(double x, long n) {
        if (n == 0)
            return 1.0;
        if (n < 0)
            return 1.0 / myPow(x, -n);
        if (n % 2 == 1)
            return x * myPow(x, n - 1);
        return myPow(x * x, n >> 1);
    }
}

Tips:

  • ⭐补充一点,n >> 1表示n的所有二进制位向右移动一位,相当于除2。

🍦Python AC代码:

class Solution(object):
    def myPow(self, x, n):
        if not n:
            return 1
        if n < 0:
            return 1 / self.myPow(x, -n)
        if n % 2:
            return x * self.myPow(x, n - 1)
        return self.myPow(x * x, n / 2)

Tips:

  • ⭐Python是动态类型的语言,因此不需要像C++和Java中一样,考虑int型边界值的问题。

💯解法二:快速幂

🍬C++ AC代码:

class Solution {
public:
    double myPow(double x, long long n) {
        double res = 1;
        if (n < 0) {
            x = 1 / x;
            n = -n;
        }
        while (n > 0) {
            if (n & 1 == 1)
                res *= x;
            x *= x;
            n >>= 1;
        }
        return res;
    }
};

Tips:

  • x *= x是自乘操作,相当于x = x * x
  • ⭐如果n<0,一个数的负n次幂相当于它的倒数的n次幂,遇到这种情况可以先让x = 1 / x

Java AC代码:

class Solution {
    public double myPow(double x, long n) {
        double res = 1;
        if (n < 0) {
            x = 1 / x;
            n = -n;
        }
        while (n > 0) {
            if ((n & 1) == 1)
                res *= x;
            x *= x;
            n >>= 1;
        }
        return res;
    }
}

Tips:

  • if ((n & 1) == 1)中的n & 1要加上括号,不然会报错。严格来说C++的位操作符也要加上括号,某些C++编译器也会报错。

🍦Python AC代码:

class Solution(object):
    def myPow(self, x, n):
        res = 1
        if n < 0:
            x = 1 / x
            n = -n;
        while n:
            if n & 1:
                res *= x
            x *= x
            n >>= 1
        return res

2.多数元素

🚀题目链接:LeetCode169.多数元素

题目:
给定一个大小为 n 的数组 nums ,返回其中的多数元素。多数元素是指在数组中出现次数 大于 ⌊ n/2 ⌋ 的元素。
你可以假设数组是非空的,并且给定的数组总是存在多数元素。

示例 1:

输入:nums = [3,2,3]
输出:3

示例 2:

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

💯解法一:分治思想

分治法有效性的证明:
假定数组长度为 n n n,多数元素为 a a a,出现次数为 f ( a ) f(a) f(a),已知: f n ( a ) > n / 2 f_n(a) > n/2 fn(a)>n/2
将数组分成两部分,长度分别为 l l l r r r,其中 l + r = n l+r = n l+r=n
若假设 f l ( a ) < = l / 2 f_l(a) <= l/2 fl(a)<=l/2 f r ( a ) < = r / 2 f_r(a) <= r/2 fr(a)<=r/2 f n ( a ) < = n / 2 f_n(a) <= n/2 fn(a)<=n/2,与已知条件相矛盾,故假设不成立;
故将原数组分成两部分,则在其中一部分出现次数最多的必定是多数元素。

🍬C++ AC代码:

class Solution {
public:
    int majorityElement(vector<int>& nums) {
        return partition(nums, 0, nums.size() - 1);
    }

    int partition(vector<int>& nums, int left, int right) {
        if (left == right)
            return nums[left];
        int major_left = partition(nums, left, (left + right) / 2);
        int major_right = partition(nums, (left + right) / 2 + 1, right);
        if (major_left == major_right)
            return major_left;
        else
            return count(nums, left, right, major_left) < count(nums, left, right, major_right) ? major_right : major_left;
    }

    int count(vector<int>& nums, int left, int right, int target) {
        int count = 0;
        for (int i = left; i <= right; i++)
            if (nums[i] == target)
                count++;
        return count;
    }
};

Tips:

  • ⭐如果左右两部分得到的多数元素相同,那最终答案就是它,,可以提前返回。
    if (major_left == major_right)
    	return major_left;
    else ...  
    

Java AC代码:

class Solution {
    public int majorityElement(int[] nums) {
        return partition(nums, 0, nums.length - 1);
    }

    public int partition(int[] nums, int left, int right) {
        if (left == right)
            return nums[left];
        int leftMajor = partition(nums, left, (left + right) / 2);
        int rightMajor = partition(nums, (left + right) / 2 + 1, right);
        if (leftMajor == rightMajor)
            return leftMajor;
        else
            return count(nums, left, right, leftMajor) < count(nums, left, right, rightMajor) ? rightMajor : leftMajor;
    }

    public int count(int[] nums, int left, int right, int target) {
        int count = 0;
        for (int i = left; i <= right; i++)
            if (nums[i] == target)
                count++;
        return count;
    }
}

🍦Python AC代码:

class Solution(object):
    def majorityElement(self, nums):
        return self.partition(nums, 0, len(nums) - 1)
        
    def partition(self, nums, left, rigth):
        if left == rigth:
            return nums[left]
        leftMajor = self.partition(nums, left, (left + rigth) / 2)
        rigthMajor = self.partition(nums, (left + rigth) / 2 + 1, rigth)
        if leftMajor == rigthMajor:
            return leftMajor
        else:
            return rigthMajor if self.count(nums, left, rigth, leftMajor) < self.count(nums, left, rigth, rigthMajor) else leftMajor;

    def count(self, nums, left, rigth, target):
        cnt = 0;
        for i in range(left, rigth + 1):
            if nums[i] == target:
                cnt = cnt + 1
        return cnt

💯解法二:投票算法

🍬C++ AC代码:

class Solution {
public:
    int majorityElement(vector<int>& nums) {
        int candidate = nums[0], vote = 1;
        for (int i = 0; i < nums.size(); i++) {
            if (nums[i] == candidate)
                vote++;
            else if (--vote == 0) {
                candidate = nums[i];
                vote = 1;
            }
        }
        return candidate;
    }
};

Tips:

  • if (--vote == 0):自减符号写在前面表示先让vote减一再进行判断。
    这段代码等价于:
    else{
    	vote--;
    	if(vote == 0) {
    		candidate = nums[i];
    		vote = 1;
       	}
    }
    

Java AC代码:

class Solution {
    public int majorityElement(int[] nums) {
        int candidate = nums[0], vote = 1;
        for (int i = 0; i < nums.length; i++) {
            if (nums[i] == candidate)
                vote++;
            else if (--vote == 0) {
                candidate = nums[i];
                vote = 1;
            }
        }
        return candidate;
    }
}

🍦Python AC代码:

class Solution(object):
    def majorityElement(self, nums):
        candidate, vote = nums[0], 1
        for num in nums[1:]:
            if num == candidate:
                vote = vote + 1
            else:
                vote = vote - 1
                if vote == 0:
                    candidate = num
                    vote = 1
        return candidate

Tips:

  • for num in nums[1:]表示遍历从下标1开始的元素。
  • ⭐这里没用像C++代码那样的++或者--来简化代码,是因为Python不支持自增与自减操作。
  • ⭐有时候在 Python 中看到存在++i这种形式,这其实不是自增,只是简单的表示正负数的正号而已。正正得正,负负得正,所以++i--i都是i

总结

┊人生在世,还不是有时笑笑人家,有时给人家笑笑┊
-林语堂 ​​​-

footer

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值