「程式碼隨想錄演算法訓練營」第二十四天 | 貪心演算法 part2

云雀AC了一整天發表於2024-08-01

122. 買賣股票的最佳時機II

題目連結:https://leetcode.cn/problems/best-time-to-buy-and-sell-stock-ii/
題目難度:中等
文章講解:https://programmercarl.com/0122.買賣股票的最佳時機II.html
影片講解:https://www.bilibili.com/video/BV1ev4y1C7na
題目狀態:貪心有點像腦筋急轉彎,靠想,沒技巧

思路:

將問題化簡為下圖:

程式碼:

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int res = 0;
        for(int i = 1; i < prices.size(); ++i) {
            res += max(prices[i] - prices[i - 1], 0);
        }
        return res;
    }
};

55. 跳躍遊戲

題目連結:https://leetcode.cn/problems/jump-game/
題目難度:中等
文章講解:https://programmercarl.com/0055.跳躍遊戲.html
影片講解:https://www.bilibili.com/video/BV1VG4y1X7kB
題目狀態:沒有思路,看題解

思路:

看跳躍覆蓋到面積是否超出陣列的長度

程式碼:

class Solution {
public:
    bool canJump(vector<int>& nums) {
        int cover = 0;
        if(nums.size() == 1) return true;
        for(int i = 0; i <= cover; ++i) {
            cover = max(nums[i] + i, cover);
            if(cover >= nums.size() - 1) return true;
        }
        return false;
    }
};

45. 跳躍遊戲II

題目連結:https://leetcode.cn/problems/jump-game-ii/
題目難度:中等
文章講解:https://programmercarl.com/0045.跳躍遊戲II.html
影片講解:https://www.bilibili.com/video/BV1Y24y1r7XZ
題目狀態:依舊沒有思路,看題解

思路:

這題和上一題有點變化,需要在加一個變數來記錄下一步的最大覆蓋面積,當這一步的覆蓋面積遍歷完之後還沒有到達終點,那麼就加步數,到下一步的最大覆蓋面積上遍歷,若當前覆蓋面積大於等於終點了,就直接退出。

程式碼:

class Solution {
public:
    int jump(vector<int>& nums) {
        if(nums.size() == 1) return 0;
        int curDistance = 0;
        int step = 0;
        int nextDistance = 0;
        for(int i = 0; i < nums.size(); ++i) {
            nextDistance = max(nums[i] + i, nextDistance);
            if(i == curDistance) {
                step++;
                curDistance = nextDistance;
                if(nextDistance >= nums.size() - 1) break;
            }
        }
        return step;
    }
};

思路二

第二種思路就是貪心演算法的思路,和上面類似,但不用比較下一步的最遠覆蓋面積了,因為如果第一步遍歷到了最大覆蓋面積的下一個位置了,說明當前覆蓋面積並沒有包括到終點,繼續加一步找最遠覆蓋面積就行。

程式碼二

class Solution {
public:
    int jump(vector<int>& nums) {
        if(nums.size() == 1) return 0;
        int curDistance = 0;
        int step = 0;
        int nextDistance = 0;
        for(int i = 0; i < nums.size() - 1; ++i) {
            nextDistance = max(nums[i] + i, nextDistance);
            if(i == curDistance) {
                step++;
                curDistance = nextDistance;
            }
        }
        return step;
    }
};

1005. K 次取反後最大化的陣列和

題目連結:https://leetcode.cn/problems/maximize-sum-of-array-after-k-negations/
題目難度:簡單
文章講解:https://programmercarl.com/1005.K次取反後最大化的陣列和.html
影片講解:https://www.bilibili.com/video/BV138411G7LY
題目狀態:久違的有思路並且透過!果然,我還是適合簡單題

思路:

遍歷 k 次,每次尋找陣列中最小的元素,將其改為相反的數,最後將陣列中的元素相加得到結果。

程式碼:

class Solution {
public:
    int largestSumAfterKNegations(vector<int>& nums, int k) {
        while(k--) {
            int minNum = INT_MAX;
            int minIdx = 0;
            for(int i = 0; i < nums.size(); ++i) {
                if(minNum > nums[i]) {
                    minNum = nums[i];
                    minIdx = i;
                }
            }
            nums[minIdx] = -nums[minIdx];
        }
        int sum = 0;
        for(auto &num : nums) sum += num;
        return sum;
    }
};

思路二:

使用貪心思維,將陣列按照絕對值從大到小的順序排列,然後將陣列中最大且為負數的值變為正數,遍歷一圈後,若 k 值還在,那就找到最小的值,反覆將其轉變正負數,直到 k 值消耗完。

程式碼二:

class Solution {
public:
    static bool cmp(int a, int b) {
        return abs(a) > abs(b);
    }
    int largestSumAfterKNegations(vector<int>& nums, int k) {
        sort(nums.begin(), nums.end(), cmp);
        for(int i = 0; i < nums.size(); ++i) {
            if(nums[i] < 0 && k > 0) {
                nums[i] *= -1;
                k--;
            }
        }
        if(k % 2 == 1) nums[nums.size() - 1] *= -1;
        int sum = 0;
        for(auto &num : nums) sum += num;
        return sum;
    }
};

相關文章