代碼隨想錄算法訓練營|第三十六天|1005.K次取反后最大化的数组和、134. 加油站、135. 分发糖果。刷题心得(c++)

目录

讀題

1005.K次取反后最大化的数组和

自己看到题目的第一想法

看完代码随想录之后的想法

134. 加油站

自己看到题目的第一想法

看完代码随想录之后的想法

135. 分发糖果

自己看到题目的第一想法

看完代码随想录之后的想法

1005.K次取反后最大化的数组和 - 實作

思路

一開始思路

代碼隨想錄思路

Code

一開始代碼

看完代碼隨想錄的代碼

134. 加油站 - 實作

思路

Code

135. 分发糖果 - 實作

思路

錯誤思路

正確思路

Code

錯誤思路代碼

正確思路代碼

總結

自己实现过程中遇到哪些困难

今日收获,记录一下自己的学习时长

相關資料


讀題

1005.K次取反后最大化的数组和

自己看到题目的第一想法

看完後的想法就是,將數組排列後,執行k次迴圈,將負數轉為正數,並記錄最小值,假設k次迴圈大於nums中的負數數量,則後續只將最小值進行正負數轉換,實際寫題遇到很多問題,經過調整後雖然code不精簡,但可以通過。

看完代码随想录之后的想法

看完之後的確自己的寫法太不精簡了,也沒有歸納出兩次的貪心策略

  1. 絕對值排序,將最大的負數進行取反操作
  2. 全部為正後,k沒有消耗完,則對最小的數值進行反覆取反操作

裡面有個部分我看到之後就學到了,就是對於第二個貪心策略,如果沒看影片前我真的會使用迴圈進行反覆取反的操作,但看完之後,才發現只需要一個判斷奇數偶數來對取反操作進行一個快速判斷。

134. 加油站

自己看到题目的第一想法

看得有點矇,不太知道要怎麼下手這一題,不像135. 分发糖果或1005.K次取反后最大化的数组和至少有個思路,這個看了二十分鐘,沒有想法。

看完代码随想录之后的想法

看完之後,看到total 跟 當前的想法我覺得真的太妙了,方法一還要再花點時間進行理解,不過方法二的做法很直覺,假設我前面的i的剩餘油量為負,那我就從i+1重新開始,跟之前最大子序和的部分有點像,並且假設我總油量大於消耗油量,那一定可以跑完全程,局部最優的策略就是假設我當前的油量為正那我就繼續執行,假設為負,那就從下一個點重新開始。

135. 分发糖果

自己看到题目的第一想法

看到題目感覺跟擺動有點像,就用一個陣列紀錄是否有變化,之後用這個陣列去針對count做++或count = 1的變換,但實際操作發現假設在一個中間有平坡的狀況會出現問題,

看完代码随想录之后的想法

看完之後就知道我自己是一次判斷左右來進行解題的,就像我在第一次解題時,會出現中間有平坡或者前後遍歷的差異,導致實際上分配是有差別的,因為要比較相鄰的元素,跟著影片看完講解後就對這道題目比較理解了。

1005.K次取反后最大化的数组和 - 實作

思路

一開始思路

  1. 將數組排列後,執行k次迴圈
  2. 將負數轉為正數,並記錄最小值
  3. 假設k次迴圈大於nums中的負數數量
  4. 後續只將最小值進行正負數轉換

代碼隨想錄思路

  • 貪心策略
    • 絕對值排序,將最大的負數進行取反操作
    • 全部為正後,k沒有消耗完,則對最小的數值進行反覆取反操作
  1. 進行絕對值排序
  2. 遍歷所有元素,假設小於零則取反
  3. 對於剩餘的k進行奇數偶數判斷,假設為奇數則對最後一個數值(最小的數值)取反操作。
  4. get 數組和

Code

一開始代碼

class Solution {
public:
    int largestSumAfterKNegations(vector<int>& nums, int k) {
        sort(nums.begin(), nums.end());
        int sum = 0;
        int min = 101;
        int remain = 0;
        for(int count = 0, i = 0; count < k; count++) {
            if(i < nums.size()) {
                int mul = 0;
                if(nums[i] < 0 ){
                    nums[i] = nums[i] * -1;
                    mul = 1;
                } 
                if(min > nums[i]) {
                    min = nums[i];
                    remain = i;
                }
                if(mul != 1) nums[remain] = nums[remain] * -1;
                i++;
            } else {
                nums[remain] = nums[remain] * -1;
            }
        }
        for(int i = 0; i < nums.size(); i++) {
            printf("nums[%d]:%d\\n",i, nums[i]);
            sum += nums[i];
        }
        return sum;
    }
};

看完代碼隨想錄的代碼

class Solution {

static bool cmp(int a, int b) {
    return abs(a) > abs(b);
}

public:
    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(int i = 0; i < nums.size(); i++) {
            sum += nums[i];
        }

        return sum;
    }
};

 

 

134. 加油站 - 實作

思路

  1. curSum 記錄到目前為止的油量
  2. totalSum 記錄整趟旅程的剩餘油量
  3. start 紀錄起始位置
  4. 遍歷所有元素
  5. 假設curSum < 0,則start 從下一個元素開始,並且初始化curSum;
  6. 假設totalSum < 0 代表不可能走完一圈,否則return start。

Code

class Solution {
public:
    int canCompleteCircuit(vector<int>& gas, vector<int>& cost) {
        int curSum = 0;
        int totalSum = 0;
        int start = 0;
        for(int i = 0; i < gas.size(); i++) {
            curSum += gas[i] - cost[i];
            totalSum += gas[i] - cost[i];
            if(curSum < 0) {
                start = i + 1;
                curSum = 0;
            }
        }
        if(totalSum < 0) return -1;

        return start;
    }
};

 

135. 分发糖果 - 實作

思路

錯誤思路

  1. 建立一個數組,紀錄左右的變化
  2. 假設diff == true 則count++ 並且加到result,否則count = 1 並加到result
  3. return result;

錯誤點: 單向遍歷,中間有平坡之類的狀況沒有考慮到

正確思路

  1. 建立Candy數組紀錄要發多少糖果,全部預設為1
  2. 由前往後遍歷,假設右比左大,當前的Candy數量為上一個Candy數量+1
  3. 由後往前遍歷,假設左比右大,比較與由前往後遍歷的Candy數量與當前的Candy數量為上一個Candy數量+1哪個較大,取較大的數值
  4. 計算Candy數組和,並回傳結果。

Code

錯誤思路代碼

class Solution {
public:
    int candy(vector<int>& ratings) {
        vector<bool> diff(ratings.size(), false);
        for(int i = 1; i < ratings.size(); i++) {
            if(ratings[i] - ratings[i - 1] > 0) diff[i] = true;
            else if (ratings[i] - ratings[i - 1] < 0) diff[i - 1] = true;
        }
        int count = 1;
        int result = 0;
        for(int i = 0; i < ratings.size(); i++) {
            if(diff[i] == true) count++;
            else count = 1;
            result += count;
        }
        return result;
    }
};

正確思路代碼

class Solution {
public:
    int candy(vector<int>& ratings) {
        vector<int> Candy(ratings.size(), 1);
        for(int i = 1; i < ratings.size(); i++) {
            if(ratings[i] > ratings[i - 1]) Candy[i] = Candy[i - 1] + 1;
        }
        for(int i = ratings.size() - 2; i >= 0 ; i--) {
            if(ratings[i] > ratings[i + 1]) Candy[i] = max(Candy[i + 1] + 1, Candy[i]);
        }
        int result = 0;
        for(int i = 0; i < Candy.size(); i++) {
            result += Candy[i];
        }
        return result;
    }
};

 

總結

自己实现过程中遇到哪些困难

今天遇到困難點的主要是加油站,加油站的確沒有想到區段和如果為負的則由下一個位置當作起始點,另外就是分發糖果,一開始的確掉到坑裡,但看完題解後,發現思路也的確不難,自己對於貪心算法真的比較矇,需要多練習,建立不同思考題目的觀察力,解貪心才會比較得心應手。

今日收获,记录一下自己的学习时长

今日大概學習了3hr,主要都在思考,實際上的代碼複雜程度反而沒有那麼高,在貪心真的思路比較重要。

相關資料

● 今日学习的文章链接和视频链接

1005.K次取反后最大化的数组和

https://programmercarl.com/1005.K次取反后最大化的数组和.html

134. 加油站

https://programmercarl.com/0134.加油站.html

135. 分发糖果

https://programmercarl.com/0135.分发糖果.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值