复习Day04:数组part04:189. 轮转数组、238. 除自身以外数组的乘积

之前的blog链接:https://blog.csdn.net/weixin_43303286/article/details/131700482?spm=1001.2014.3001.5501

我用的方法是在leetcode再过一遍例题,明显会的就复制粘贴,之前没写出来就重写,然后从拓展题目中找题目来写。辅以Labuladong的文章看。然后刷题不用CLion了,使用leetcode自带模拟面试环境。

189. 轮转数组

给定一个整数数组 nums,将数组中的元素向右轮转 k 个位置,其中 k 是非负数。

 

示例 1:

输入: nums = [1,2,3,4,5,6,7], k = 3
输出: [5,6,7,1,2,3,4]
解释:
向右轮转 1: [7,1,2,3,4,5,6]
向右轮转 2: [6,7,1,2,3,4,5]
向右轮转 3: [5,6,7,1,2,3,4]
示例 2:

输入:nums = [-1,-100,3,99], k = 2
输出:[3,99,-1,-100]
解释: 
向右轮转 1: [99,-1,-100,3]
向右轮转 2: [3,99,-1,-100]
 


自己想出来两种解法,一种是重新使用额外数组,一种是使用先翻转整体再反转局部:

class Solution {
public:
    void rotate(vector<int>& nums, int k) {
        // //方法1:使用一个新数组
        // int n = nums.size();
        // vector res;
        // k = k % n;
        // for(int i = n - k; i < n; i++){
        //     res.push_back(nums[i]);
        // }
        // for(int i = 0; i < n - k; i++){
        //     res.push_back(nums[i]);
        // }
        // nums = res;

        
        //先整体翻转,再部分reverse
        k = k % nums.size();
        reverse(nums.begin(), nums.end());
        reverse(nums.begin(), nums.begin() + k);
        reverse(nums.begin() + k, nums.end());

    }
};

官方题解还有一种基于数学推导的:

复习Day04:数组part04:189. 轮转数组、238. 除自身以外数组的乘积_第1张图片

复习Day04:数组part04:189. 轮转数组、238. 除自身以外数组的乘积_第2张图片

最终代码:

class Solution {
public:
    void rotate(vector<int>& nums, int k) {
        int n = nums.size();
        k = k % n;
        int count = gcd(k, n);
        for (int start = 0; start < count; ++start) {
            int current = start;
            int prev = nums[start];
            do {
                int next = (current + k) % n;
                swap(nums[next], prev);
                current = next;
            } while (start != current);
        }
    }
};

这个我肯定想不出来,但时间复杂度和两次反转一样都是O(n),空间复杂度都是O(1)。

238. 除自身以外数组的乘积

给你一个整数数组 nums,返回 数组 answer ,
其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。

题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在32 位 整数范围内。

请 不要使用除法,且在 O(n) 时间复杂度内完成此题。

 

示例 1:

输入: nums = [1,2,3,4]
输出: [24,12,8,6]
示例 2:

输入: nums = [-1,1,0,-3,3]
输出: [0,0,9,0,0]

首先是暴力解法,因为这题不能使用乘法,二重循环遍历,很好想象超时了:

class Solution {
public:
    vector<int> productExceptSelf(vector<int>& nums) {
        vector<int> answer;
        int sup;
        for(int i = 0; i < nums.size(); i++){
            int sup = 1;
            for(int j = 0; j < nums.size(); j++){
                if(i == j){
                    continue;
                }
                sup *= nums[j];

            }
            answer.push_back(sup);
        }
        return answer;
    }
};

还有一种方法是先求出所有元素的和,再分别/nums[i],这个用了除法肯定是过不了的。

这里使用评论区一个非常巧妙的解法:双指针解法

class Solution {
public:
    vector<int> productExceptSelf(vector<int>& nums) {
        int n  = nums.size();
        vector<int> answer(n , 1);
        int beforeSum = 1, afterSum = 1;
        for(int i = 0, j = n - 1; i < n; i++, j--){
            answer[i] *= beforeSum;
            answer[j] *= afterSum;
            beforeSum *= nums[i];
            afterSum *= nums[j];
        }
        return answer;
    }
};

这个思路和之前的接雨水相似,都是从两头逼近,明天把前缀和相关的代码看一遍。

你可能感兴趣的:(算法)