Leetcode初体验生存向——Day5

41. First Missing Positive(Hard)

Question:

Given an unsorted integer array, find the smallest missing positive integer.

Example 1:

Input: [1,2,0]
Output: 3

Example 2:

Input: [3,4,-1,1]
Output: 2

Example 3:

Input: [7,8,9,11,12]
Output: 1

Follow up:

Your algorithm should run in O(n) time and uses constant extra space.

Solution:

/**
 * 思路:用符号做标记,完全数学思路
 * 哈希表支持快速查找,因此可以将数组放到哈希表中
 * 而对于一个长度为n的数组,没有出现的最小正整数只能在[1,n+1]中
 * 例如:[1234]长度为4,最小正整数为n+1=5
 *       [1345]长度为4,最小正整数为2
 * 如此一来,如果[1,n]都出现了,说明结果为n+1;否则在[1,n]中某一个位置
 * 既然如此,将所有[1,n]范围内的数放入哈希表
 * 对数组进行遍历,对于遍历到的数x,如果在[1,n]范围内,就给它的第x-1个位置打上标记
 * 如果所有的位置都被打上标记了,答案就是n+1,否则就是最小的没有标记的位置+1
 * 这里打标记的方法就是加一个负号
 * 本质上就是给数字进行重新排序
 * 如:[3 4 -1 1 9 -5]
 *     首先为了排除原有负数的干扰,要将负数变为正数
 *     因为只标记位于[1,n]的数,因此把所有的附属变为n+1即可,这里n=6,将负数变为7
 *     [3 4 7 1 9 7]
 *     接下来是打标记,只关注[1,n]之间的数,首先是3,将第3个,即第2位的数字加负号
 *     [3 4 -7 1 9 7] 标记一下3有了
 *     下一个是4,将第4个,即第3位数字加负号
 *     [3 4 -7 -1 9 7] 标记一下4有了
 *     7大于n,跳过,下一个是1,将第1个即第0位数字加负号
 *     [-3 4 -7 -1 9 7] 标记一下1有了
 *     9和7均大于n,跳过
 *     最后的结果是有1,3,4,最小正整数没有2
 *     因此返回1位+1=2
 */
class Solution {
    public int firstMissingPositive(int[] nums) {
        int n = nums.length;

        // 把所有负数改为n+1
        for (int i = 0 ; i < n ; i++) {
            if (nums[i] <= 0) {
                nums[i] = n + 1;
            }
        }

        // 开始标记
        for (int i = 0 ; i < n ; i++) {
            int num = Math.abs(nums[i]); // 记得加绝对值,避免已经标记过的负数干扰
            if (num <= n) {
                nums[num - 1] = -Math.abs(nums[num - 1]);
            }
        }

        // 找到第一位正整数,返回位数+1
        for (int i = 0 ; i < n ; i++) {
            if (nums[i] > 0) {
                return i + 1;
            }
        }

        // 如果全被标记,返回n+1
        return n + 1;
    }
}

链接:https://leetcode-cn.com/problems/first-missing-positive

42. Trapping Rain Water(Hard)

Question:

Given n non-negative integers representing an elevation map where the width of each bar is 1, compute how much water it is able to trap after raining.

The above elevation map is represented by array [0,1,0,2,1,0,1,3,2,1,2,1]. In this case, 6 units of rain water (blue section) are being trapped. Thanks Marcos for contributing this image!

Example:

Input: [0,1,0,2,1,0,1,3,2,1,2,1]
Output: 6

Solution:

/**
 * 思路:双指针
 * 妙到让我无言以对
 * 观察规律发现:
 * 从左边起,当右块比前左块要矮的时候,说明它有盛水的可能性
 * 当抵达一块比左边界高的方块时,就盛好一次水了
 * 因此这里需要不断更新左边的最大值,来判断左右边界
 * 比前一个矮的就盛水,比最大值高的就不盛水,更新最大值,准备下一轮盛水
 * 右侧同理,当左块比后右块要矮的时候,就盛水,左块比最大值高时不盛水,更新最大值,准备下一轮
 * 那么如何知道后面一定会有比前面的边界高的方块呢:
 * 这里左右指针是分别从两边开始向中间移动的,可以对左右指针做判断
 * 如果左指针的方块比右指针的方块高,则说明左边一定有可以给右边盛水的边界,移动右指针
 * 如果右指针的方块比左指针的高,则说明右边一定有可以给左边盛水的边界,移动左指针
 */
class Solution {
    public int trap(int[] height) {
        int len = height.length;
        int left = 0; // 左指针从第一位开始右移
        int right = len - 1; // 右指针从最后一位开始左移
        int ans = 0; // 初始化结果
        int leftMax = 0; // 左边最大值
        int rightMax = 0; //右边最大值

        // 结束条件为左右指针相碰
        while (left < right) {
            // 如果左指针比右指针方块矮,说明左边能盛水,移动左指针
            if (height[left] < height[right]) {
                // 如果左指针方块比最大值高或等于(可能出现同等高度的一个平面),更新
                if (height[left] >= leftMax) leftMax = height[left];
                // 只要比最大值(此时最大值就是左边界)矮,算作积水的体积
                else ans += leftMax - height[left];
                // 移动左指针
                left++;
            }
            // 如果左指针比右指针方块高,说明右边能盛水,移动右指针
            else {
                // 如果右指针方块比最大值高或等于(可能出现同等高度的一个平面),更新
                if (height[right] >= rightMax) rightMax = height[right];
                // 只要比最大值(此时最大值就是右边界)矮,算作积水的体积
                else ans += rightMax - height[right];
                // 移动右指针
                right--;
            }
        }
        return ans;
    }
}

链接:https://leetcode-cn.com/problems/trapping-rain-water

43. Multiply Strings(Middle)

Question:

Given two non-negative integers num1 and num2 represented as strings, return the product of num1 and num2, also represented as a string.

Example 1:

Input: num1 = “2”, num2 = “3”
Output: “6”

Example 2:

Input: num1 = “123”, num2 = “456”
Output: “56088”

Note:

  1. The length of both num1 and num2 is < 110.
  2. Both num1 and num2 contain only digits 0-9.
  3. Both num1 and num2 do not contain any leading zero, except the number 0 itself.
  4. You must not use any built-in BigInteger library or convert the inputs to integer directly.

Solution:

/**
 * 这道题的思路是卷积(伪)你敢信
 * 参考:https://leetcode-cn.com/problems/multiply-strings/solution/zi-fu-chuan-xiang-cheng-by-leetcode-solution/
 * 设num1长度为m,num2长度为n,乘积长度为m+n-1或m+n,证明参考链接
 * 因此设存放结果集的数组长度为m+n
 * 对于任意0<=i<m和0<=j<n,num1[i]*num2[j]的结果位于ans[i+j+1]
 * 如果ansArr[i+j+1]>=10,就把进位的地方加到ans[i+j]
 */
class Solution {
    public String multiply(String num1, String num2) {
        // 任何数乘0都为0
        if (num1.equals("0") || num2.equals("0")) {
            return "0";
        }
        // 初始化长度,结果集
        int m = num1.length();
        int n = num2.length();
        int[] ans = new int[m+n];
        // 把对应num1[i]*num2[j]的结果存入数组ans[i+j+1]位置,先不管进位
        // 如123*456
        // ans[2+2+1]=18,ans[2+1+1]=15,ans[2+0+1]=12
        // ans[1+2+1]=ans[2+1+1]+12=15+12,ans[1+1+1]=ans[2+0+1]+10=12+10,ans[1+0+1]=8
        // ans[0+2+1]=ans[1+1+1]+6=12+10+6,ans[0+1+1]=ans[1+0+1]+5=8+5,ans[0+0+1]=4
        // 所以结果应为ans[1]=4,ans[2]=13,ans[3]=28,ans[4]=27,ans[5]=18
        for (int i = m - 1 ; i >= 0 ; i--) {
            int x = num1.charAt(i) - '0'; // 将字符变为int
            for (int j = n - 1 ; j >= 0 ; j--) {
                int y = num2.charAt(j) - '0'; // 将字符变为int
                ans[i + j + 1] += x * y;
            }
        }
        // 将数组中的数按位处理
        // 把该进位的拿出来
        // 像这个样子:1 2 3 4 5
        // ans[5]=           1 8
        // ans[4]=         2 7
        // ans[3]=       2 8
        // ans[2]=     1 3
        // ans[1]=     4
        // i>0是为了避免ans[i-1]越界,即数组位数应当是012345,乘积长度为m+n或m+n-1,如果只有m+n-1那么长,第0为0
        for (int i = m + n - 1 ; i > 0 ; i--) {
            ans[i-1] += ans[i] / 10;
            ans[i] %= 10;
        }
        // 第0为0,说明长度为m+n-1,从第1位开始写String
        // 第0不为0,说明长度为m+n,从第0位开始写String
        int index = ans[0] == 0 ? 1 : 0;
        StringBuffer ansStr = new StringBuffer();
        while (index < m + n) {
            ansStr.append(ans[index]);
            index++;
        }
        return ansStr.toString();
    }
}

链接:https://leetcode-cn.com/problems/multiply-strings

44. Wildcard Matching(Hard)

Question:

Given an input string (s) and a pattern §, implement wildcard pattern matching with support for ‘?’ and ‘*’.

'?' Matches any single character.
'*' Matches any sequence of characters (including the empty sequence).

The matching should cover the entire input string (not partial).

Note:

  • s could be empty and contains only lowercase letters a-z.
  • p could be empty and contains only lowercase letters a-z, and characters like ? or *.

Example 1:

Input:
s = “aa”
p = “a”
Output: false
Explanation: “a” does not match the entire string “aa”.

Example 2:

Input:
s = “aa”
p = ""
Output: true
Explanation: '
’ matches any sequence.

Example 3:

Input:
s = “cb”
p = “?a”
Output: false
Explanation: ‘?’ matches ‘c’, but the second letter is ‘a’, which does not match ‘b’.

Example 4:

Input:
s = “adceb”
p = “ab”
Output: true
Explanation: The first ‘’ matches the empty sequence, while the second '’ matches the substring “dce”.

Example 5:

Input:
s = “acdcb”
p = “a*c?b”
Output: false

Solution:

/**
 * 与第10题类似,唯一不同的是*不用受前一字符影响,可以随意匹配字符
 * 很明显是动态规划
 * 状态定义:
 *      状态表dp[i][j]表示p的前i个字符与s的前j个字符是否匹配
 *      i是匹配串p的下标,j是给定字符串s的下标
 * 状态转移:
 *      1.如果p[i-1]==s[j-1]||p[i-1]=='?',当前字符串匹配(也就是从p[0]s[0]开始全部匹配到p[i-1]s[j-1])
 *        那么dp[i][j]可以从dp[i-1][j-1]进行状态转移
 *        白话就是前面的都匹配,后面的可以继续匹配;如果前面出现不匹配的,后面就算匹配也是错的,所以不能状态转移
 *      2.如果p[i-1]=='*',那这个位置可以匹配0到若干个字符
 *        dp[i][j]可以从dp[i-1][j]转移,表示当前星号没有匹配字符,直接跳过星号,就相当于匹配了空字符串
 *        dp[i][j]可以从dp[i][j-1]转移,表示当前星号匹配了一个字符
 *        只要任意一种匹配就行,所以是逻辑或关系
 * 初始条件:
 *      dp[0][0]=true表示空串匹配
 */
class Solution {
    public boolean isMatch(String s, String p) {
        int len1 = p.length();
        int len2 = s.length();

        boolean[][] dp = new boolean[len1 + 1][len2 + 1]; // 初始化状态表,留出一行一列是为状态初始化做准备
        dp[0][0] = true; // 用到自顶向下法,初始化状态为true(代表空字符串匹配)

        // 解决一下一上来就遇到*的问题
        for (int i = 1 ; i <= len1 ; i++) {
            if (p.charAt(i - 1) != '*') {
                // 一上来没有'*'直接结束循环,继续后面的程序
                break;
            }
            // 一上来有'*',往后挪,挪到没有'*'为止,与s匹配
            // 不要担心开头的'*'与s的开头匹配的问题,后面会对它做验证
            dp[i][0] = true;
        }

        // 状态转移
        for (int i = 1 ; i <= len1 ; i++) {
            for (int j = 1 ; j <= len2 ; j++) {
                if (p.charAt(i - 1) == s.charAt(j - 1) || p.charAt(i - 1) == '?') {
                    dp[i][j] = dp[i - 1][j - 1];
                }
                // 这里判断'*',s和p匹配不上了,就看p的前一位是不是*,因为刚才*都被略去了,所以要找前一位
                else if (p.charAt(i - 1) == '*') {
                    dp[i][j] = dp[i - 1][j] || dp[i][j - 1]; // 注意这里是逻辑或关系
                }
            }
        }
        return dp[len1][len2];
    }
}

链接:https://leetcode-cn.com/problems/wildcard-matching

45. Jump Game II(Hard)

Question:

Given an array of non-negative integers, you are initially positioned at the first index of the array.

Each element in the array represents your maximum jump length at that position.

Your goal is to reach the last index in the minimum number of jumps.

Example:

Input: [2,3,1,1,4]
Output: 2
Explanation: The minimum number of jumps to reach the last index is 2.
Jump 1 step from index 0 to 1, then 3 steps to the last index.

Note:

You can assume that you can always reach the last index.

Solution:

/**
 * 贪心算法
 * 用到了边界条件,妙啊
 * 贪心算法只专注于当前局部最优,在这道题也就是只维护当前能到达的最大下标位置
 * 将当前能到达的最大位置记为边界,从左到右遍历数组,当到达边界时,更新边界,跳跃次数加1
 */
class Solution {
    public int jump(int[] nums) {
        int len = nums.length;
        int end = 0; // 初始化边界(也是下一步的起跳点)
        int maxPosition = 0; // 随时记录当前能到达下标的最大值
        int steps = 0; // 记录步数
        // 开始贪心算法
        // i<len-1是因为到倒数第二步的时候,倒数第二个元素肯定大于等于最后一个位置,所以到倒数第二个就够了
        for (int i = 0 ; i < len - 1 ; i++) {
            maxPosition = Math.max(maxPosition, i + nums[i]); // 一直保持当前最优
            // 到达边界就走下一步,找下一个最大值
            if (i == end) {
                end = maxPosition;
                steps++;
            }
            // 一个优化,起跳点到达或超过终点就可以直接停了,不用再找了
            if (end >= len - 1) {
                break;
            }
        }
        return steps;
    }
}

链接:https://leetcode-cn.com/problems/jump-game-ii

46. Permutations(Middle)

Question:

Given a collection of distinct integers, return all possible permutations.

Example:

Input: [1,2,3]
Output:
[
[1,2,3],
[1,3,2],
[2,1,3],
[2,3,1],
[3,1,2],
[3,2,1]
]

Solution:

/**
 * 显而易见的回溯法+巧妙的移行换位法
 * 画图理解,参考:https://leetcode-cn.com/problems/permutations/solution/quan-pai-lie-by-leetcode-solution-2/
 * 这里纠正一下前面理解上的一个错误
 * 回溯的时候一般都会定义两个ArrayList
 * 一个是嵌套的,往往是List<List<Integer>>这种形式,很明显是结果集,输出结果是[[],[],[]]这种亚子
 * 一个是单独的,List<Integer>这种形式,我刚开始以为它是要放入结果集的,实际是回溯的时候用的
 * 这就解释了为什么在往结果集加东西的时候要new一个list,这里仅仅把当前数据放了进去,放完之后回溯,它里面的内容又会更改
 */
class Solution {

    // 回溯
    private void backtrack(int len, List<Integer> temp, List<List<Integer>> res, int first) {

        // 当所有数都填完了,把当前结果塞进结果集
        if (first == len) {
            res.add(new ArrayList<Integer>(temp));
        }

        // 移形换位,定义一个新的指针,用来交换数字
        for (int i = first ; i < len ; i++) {
            Collections.swap(temp, first, i); // 这个方法是交换temp集中位于first和位于i的两位数
            // 递归填下一个数字
            backtrack(len, temp, res, first + 1);
            // 回溯,相当于把刚才交换的换回去
            Collections.swap(temp, first, i); 
        }
    }

    public List<List<Integer>> permute(int[] nums) {
        // 先定义一下结果集
        List<List<Integer>> res = new ArrayList<List<Integer>>();
        // 定义一下一会回溯的时候用的数组
        List<Integer> temp = new ArrayList<Integer>();
        // 在temp中放入初始序列(按顺序),即nums,如[1,2,3],一会换位置就换它
        for (int num : nums) {
            temp.add(num);
        }
        int len = nums.length;
        // 回溯,数字从0位开始填
        backtrack(len, temp, res, 0);
        return res;
    }
}

链接:https://leetcode-cn.com/problems/permutations

47. Permutations II(Middle)

Question:

Given a collection of numbers that might contain duplicates, return all possible unique permutations.

Example:

Input: [1,1,2]
Output:
[
[1,1,2],
[1,2,1],
[2,1,1]
]

Solution:

/**
 * 仍然是回溯(没有移行换位),加一个去重
 */
class Solution {

    // 回溯
    private void backtrack(int len, List<Integer> temp, List<List<Integer>> res, boolean[] used, int first, int[] nums) {

        // 当所有数都填完了,把当前结果塞进结果集
        if (first == len) {
            res.add(new ArrayList<Integer>(temp));
            return;
        }

        // 这里注意i从0开始,因为没有用移形换位,要得到全排列,拿后面的数字做第一位时还要考虑前面的数字
        for (int i = 0 ; i < len ; i++) {
            // 使用过该元素,跳过
            if (used[i]) continue;
            // 剪枝
            // i>0 是为了让 nums[i-1] 不越界
            // 注意这里是nums里的数字做对比,而不是得到的结果里面数字做对比
            // nums里数字做对比是为了避免同层重复,如[1(第一位),1(第二位),2]和[1(第二位),1(第一位),2]
            if (used[i] || (i > 0 && nums[i] == nums[i-1] && !used[i-1])) continue;
            temp.add(nums[i]); // 填数字
            used[i] = true; // 标记一下这位数字用过了(标记的是nums中的用过没)
            // 递归填下一个数字
            backtrack(len, temp, res, used, first + 1, nums);
            // 回溯,去掉填的数字(记得把使用状态改为false)
            temp.remove(first);
            used[i] = false;
        }
    }

    public List<List<Integer>> permuteUnique(int[] nums) {
        // 先定义一下结果集
        List<List<Integer>> res = new ArrayList<List<Integer>>();
        // 定义一下一会回溯的时候用的数组
        List<Integer> temp = new ArrayList<Integer>();
        int len = nums.length;
        // 判断一下用过没
        boolean[] used = new boolean[len];
        // 排序,确保相等的元素相邻
        Arrays.sort(nums);
        // 回溯,数字从0位开始填
        backtrack(len, temp, res, used, 0, nums);
        return res;
    }
}

链接:https://leetcode-cn.com/problems/permutations-ii

48. Rotate Image(Middle)

Question:

You are given an n x n 2D matrix representing an image, rotate the image by 90 degrees (clockwise).

You have to rotate the image in-place, which means you have to modify the input 2D matrix directly. DO NOT allocate another 2D matrix and do the rotation.

Example 1:

Input: matrix = [[1,2,3],[4,5,6],[7,8,9]]
Output: [[7,4,1],[8,5,2],[9,6,3]]

Example 2:

Input: matrix = [[5,1,9,11],[2,4,8,10],[13,3,6,7],[15,14,12,16]]
Output: [[15,13,2,5],[14,3,4,1],[12,6,8,9],[16,7,10,11]]

Example 3:

Input: matrix = [[1]]
Output: [[1]]

Example 4:

Input: matrix = [[1,2],[3,4]]
Output: [[3,1],[4,2]]

Constraints:

  • matrix.length == n
  • matrix[i].length == n
  • 1 <= n <= 20
  • -1000 <= matrix[i][j] <= 1000

Solution:

/**
 * 先矩阵转置,再翻转每一行
 */
class Solution {
    public void rotate(int[][] matrix) {
        int len = matrix.length;

        // 矩阵转置
        for (int i = 0 ; i < len ; i++) {
            for (int j = i ; j < len ; j++) {
                int temp = matrix[i][j];
                matrix[i][j] = matrix[j][i];
                matrix[j][i] = temp;
            }
        }

        // 翻转每一行
        for (int i = 0 ; i < len ; i++) {
            for (int j = 0 ; j < len / 2 ; j++) {
                int temp = matrix[i][j];
                matrix[i][j] = matrix[i][len - j - 1];
                matrix[i][len - j - 1] = temp;
            }
        }
    }
}

链接:https://leetcode-cn.com/problems/rotate-image

49.Group Anagrams(Middle)

Question:

Given an array of strings strs, group the anagrams together. You can return the answer in any order.

An Anagram is a word or phrase formed by rearranging the letters of a different word or phrase, typically using all the original letters exactly once.

Example 1:

Input: strs = [“eat”,“tea”,“tan”,“ate”,“nat”,“bat”]
Output: [[“bat”],[“nat”,“tan”],[“ate”,“eat”,“tea”]]

Example 2:

Input: strs = [""]
Output: [[""]]

Example 3:

Input: strs = [“a”]
Output: [[“a”]]

Constraints:

  • 1 <= strs.length <= 104
  • 0 <= strs[i].length <= 100
  • strs[i] consists of lower-case English letters.

Solution:

官方给了两种方法,参考:
https://leetcode-cn.com/problems/group-anagrams/solution/zi-mu-yi-wei-ci-fen-zu-by-leetcode/

两种都很巧妙,第一种是排序数组分类:

/**
 * 第一种:
 *        给一个映射ans:{String -> List}
 *        把每一个字符串数组strs中的字符串都用toCharArray方法打散成为字符数组ca
 *        对字符数组ca进行重排序
 *        映射ans中存放的key就是重排序后的字符数组ca,看一下ans中的key有没有重排序后的ca
 *        如果没有,把重排序的ca放进去,然后对应的原字符串放进去作为value
 *        如果有,直接把对应的原字符串放到key为ca的value中(value本身就是list)
 */
class Solution {
    public List<List<String>> groupAnagrams(String[] strs) {
        // 空字符串直接返回空
        if (strs.length == 0) return new ArrayList();
        // 初始化映射ans:{String -> List}
        Map<String, List> ans = new HashMap<String, List>();
        // 开始一个个对比给出的strs数组中的字符串s
        for (String s : strs) {
            char[] ca = s.toCharArray(); // 把s打散变为字符数组,如s='eat' -> ca=[e,a,t]
            Arrays.sort(ca); // 把ca字符数组重排列,如ca=[e,a,t] -> ca=[a,e,t]
            String key = String.valueOf(ca); // 把重排列后的字符数组变为字符串, 如ca[a,e,t] -> key='aet'
            // 看一下ans映射里有没有key='aet',没有就把key放进去,然后初始化一下list,再把当前的原始字符串s放到对应key的value里
            // 如果有key的话,直接把s塞进去就行了
            if (!ans.containsKey(key)) ans.put(key, new ArrayList());
            ans.get(key).add(s);
        }
        return new ArrayList(ans.values());
    }
}

第二种是按计数分类:

/**
 * 通俗的说就是把26个字母的数目都设为0,对应字符串给26个字母计数,数目相同的字符串是一组
 */
class Solution {
    public List<List<String>> groupAnagrams(String[] strs) {
    	// 空字符串直接返回空
        if (strs.length == 0) return new ArrayList();
        // 初始化映射ans:{String -> List}
        Map<String, List> ans = new HashMap<String, List>();
        // 初始化26个字母计数器
        int[] count = new int[26];
        // 开始计数
        for (String s : strs) {
            Arrays.fill(count, 0); // 把count数组用0填满,也就是所有的字母计数都初始化为0
            // 把strs数组中的字符串s打散为字符数组c,对应字母位置计数
            for (char c : s.toCharArray()) count[c - 'a']++;
			// 下面就是把计数后的26个字母计数器用#隔开连成一个字符串key
			// 看看ans映射中有没有key,没有的话先把key放进去,初始化list,再放对应的字符串
			// 有的话直接把对应的字符串塞进去
            StringBuilder sb = new StringBuilder("");
            for (int i = 0; i < 26; i++) {
                sb.append('#');
                sb.append(count[i]);
            }
            String key = sb.toString();
            if (!ans.containsKey(key)) ans.put(key, new ArrayList());
            ans.get(key).add(s);
        }
        return new ArrayList(ans.values());
    }
}

两种方法的区别在于,第一种要排序(Arrays.sort()),因此在时间复杂度上多一个log

如果字符串短的话,使用第一种方法最好;字符串长的话,使用第二种方法最好

链接:https://leetcode-cn.com/problems/group-anagrams

50. Pow(x, n)(Middle)

Question:

Implement pow(x, n), which calculates x raised to the power n (i.e. xn).

Example 1:

Input: x = 2.00000, n = 10
Output: 1024.00000

Example 2:

Input: x = 2.10000, n = 3
Output: 9.26100

Example 3:

Input: x = 2.00000, n = -2
Output: 0.25000
Explanation: 2-2 = 1/22 = 1/4 = 0.25

Constraints:

  • -100.0 < x < 100.0
  • -231 <= n <= 231-1
  • -104 <= xn <= 104

Solultion:

/**
 * 数学方法:分治,递归去做
 * 例如x的77次方:x77 <- x38 <- x19 <- x9 <- x4 <- x2 <- x
 * 也就是对x的次幂折半,最后就相当于是y*y
 * 如果是单数折半,要多乘一个x
 * 如:x77就是y=x38时y*y*x得出的
 * 
 * 官方解答还给出一种通过二进制解题的方法,很妙
 * 参考:https://leetcode-cn.com/problems/powx-n/solution/powx-n-by-leetcode-solution/
 */

class Solution {

    // 快速幂解法
    private double quickMultiply(double x, int n) {
        // 如果次幂是0,得出的结果都是1
        if (n == 0) return 1.0;
        // 定义y
        double y = quickMultiply(x, n / 2);
        return n % 2 == 0 ? y * y : y * y * x;
    }

    public double myPow(double x, int n) {
        // 考虑次幂为负数的情况
        return n >= 0 ? quickMultiply(x, n) : 1.0 / quickMultiply(x, -n);
    }
}

链接:https://leetcode-cn.com/problems/powx-n

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值