---
# System prepended metadata

title: 【Leetcode C++ 解題筆記】Greedy - part 1
tags: [程式設計, C++, 競程, 演算法, CP]

---

【Leetcode C++ 解題筆記】Greedy - part 1
===

[TOC]

本筆記僅供個人學習用途，內容斟酌參考。

## [409. Longest Palindrome](https://leetcode.com/problems/longest-palindrome/?envType=problem-list-v2&envId=greedy)

difficulty : Easy.

tags : hashtable, string, greedy.

題目敘述：

給定一個由大寫或小寫所組成的字串 s，回傳那些可以由字母所組成最長回文的長度。

字母是區分大小寫的，如 `Aa` 不被視為一種回文。

解題思路：

建立一個 hashtable (unordered_map)，計算每個字母所出現的次數。

- 如果次數是偶數：表示可以對稱放在回文的左右兩邊，可以全部使用，所以直接將次數加進去 len 裡面。
- 若次數是奇數：因為回文有對稱性，所以只能用偶數部分（次數 - 1）放在左右兩邊，剩下的字母可置於回文中間。（整個回文只能有一個這樣的字母在中間）

solution ( 0 ms )：

```cpp=
class Solution {
public:
    int longestPalindrome(string s) {
        
        unordered_map <char, int> f;
        
        for (char c : s){
            f[c]++;
        }
        
        int len = 0;
        bool odd_found = false;

        for (auto& p : f){
            if (p.second % 2 == 0){
                len += p.second;
            }
            else{
                len += p.second - 1;
                odd_found = true;
            }
        }

        if (odd_found) len++;

        return len;
    }
};
```

## [2037. Minimum Number of Moves to Seat Everyone](https://leetcode.com/problems/minimum-number-of-moves-to-seat-everyone/?envType=problem-list-v2&envId=greedy)

difficulty : Easy.

tags : Array, Greedy, Sorting, Counting Sort

題目敘述：

有 n 個空座位及 n 個學生，他們都站在一個房間裡。給定一個長度為 n 的陣列 seats，`seats[i]` 為在第 i 個座位的位置；也給定一個長度為 n 的陣列 students，`students[j]` 為在第 j 個學生的位置。

然後叫你紀錄從 `seats[i]` 到 `students[j]` 的距離是多少，回傳將這些距離加起來最短的和。

解題思路：

sort 兩個 vector，迴圈跑一次算 `abs(seats[i] - students[i])`，相加後就是答案。

solution ( 0ms ) :

```cpp=
class Solution {
public:
    int minMovesToSeat(vector<int>& seats, vector<int>& students) {
        sort(seats.begin(), seats.end());
        sort(students.begin(), students.end());
        int move = 0;
        for (int i = 0; i < seats.size(); i++){
            move += abs(seats[i] - students[i]);
        }
        return move;
    }
};
```

## [1221. Split a String in Balanced Strings](https://leetcode.com/problems/split-a-string-in-balanced-strings/?envType=problem-list-v2&envId=greedy)

difficulty : Easy.

tags : String, Greedy, Counting

題目敘述：

所謂平衡字串（Balanced string）就是兩字元 `'L', 'R'` 的數量相等。

給定一個字串 s，拆分成一些子字串使得：

- 每個子字串都被平衡

回傳最大可以獲得的平衡字串數量。

解題思路：

遍歷 s，看要設定成是遇到 L 就 ++，還是 R 就 ++，都可以，反正只要一增，另外一個就減。

每次遍歷要檢查 balance 是否 == 0，是的話表示平衡，count++。

solution ( 0ms ) :

```cpp=
class Solution {
public:
    int balancedStringSplit(string s) {
        int count = 0, balance = 0;
        for (const char& c : s){
            if (c == 'L'){
                balance++;
            }
            else{
                balance--;
            }
            if (balance == 0){
                count++;
            }
        }
        return count;
    }
};
```

## [2160. Minimum Sum of Four Digit Number After Splitting Digits](https://leetcode.com/problems/minimum-sum-of-four-digit-number-after-splitting-digits/?envType=problem-list-v2&envId=greedy)

difficulty : Easy.

tags : Math, Greedy, Sorting

題目敘述：

給四位數正整數，將四位數拆分成四個一位數，求將這些一位數排列組合後，使得 new1 跟 new2 的總和最小？

new1 和 new2 最多可以是三位數，最低為一位數，兩位數與兩位數也可。

如 2932 拆成 2、9、3、2，可以組成 29、32 相加，也可以組成 22、39 相加，求得兩者相加的最小和。

解題思路：

用 while 迴圈，四位數取模（`%10`）的結果放入陣列裡面，接下來再對原四位數砍一位數（`num /= 10`），再繼續取模，直到迴圈跑完為止。

最後是 new1 跟 new2 的相加，一位數加上三位數肯定比兩位加兩位大，所以這兩個變數都是兩位加兩位。

但是在此之前可以先排序陣列，比較好操作。new1 跟 new2 的十位數一定要取最小的那兩個，之後個位數隨便怎麼排都沒差。

Solution ( 0 ms ) :

```cpp=
class Solution {
public:
    int minimumSum(int num) {
        int i = 4;
        vector <int> nums(i);
        while (i--){
            nums[i] = num % 10;
            num /= 10;
        }
        sort(nums.begin(), nums.end());
        int d1 = nums[0]*10 + nums[2];
        int d2 = nums[1]*10 + nums[3];
        return d1 + d2;
    }
};
```

## [2864. Maximum Odd Binary Number](https://leetcode.com/problems/maximum-odd-binary-number/?envType=problem-list-v2&envId=greedy)

difficulty : Easy.

tags : Math, String, Greedy

題目敘述：

給定一個必定至少含有一個 1 的字串 s。

你必須要重新排列這些位元，使其組合成一個最大的奇數二進位數字。

回傳一個字串，表示可以從給定組合中得到的最大奇數二進位數字。

解題思路：

設兩個變數，用 range-based for loop 去計算 1 跟 0 在字串 s 的次數。

因為是「二進位」，所以能不能是奇數，在最末端是致關重要的一件事，如：`0101`，最後面的 1 意即 $1 \times 2^0 = 1$ 。

因此，在算完次數後，記得要再讓紀錄 1 次數的變數 `--`，因為那一次被拿去放到最後面了。

最後用 result 字串變數儲存結果，在算完 1 後加上剩下的 0，最後再補個 1。

Solution ( 0 ms ) :

```cpp=
class Solution {
public:
    string maximumOddBinaryNumber(string s) {
        int count_1 = 0, count_0 = 0;
        for (char c : s){
            if (c == '1') count_1++;
            else count_0 ++;
        }

        count_1--;
        
        string result(count_1, '1');
        
        result += string(count_0, '0');
        result += '1';

        return result;
    }
};
```

## [1323. Maximum 69 Number](https://leetcode.com/problems/maximum-69-number/?envType=problem-list-v2&envId=greedy)

difficulty : Easy.

tags : Math, Greedy

這是一個蠻有趣的題目XD

題目敘述：

給定一個僅由 6 跟 9 所組成的正整數 num。

你只能改變一個位數的狀態，如 6 改成 9，9 改成 6，試找出改完後最大的值為何？

解題思路：

將位數存入陣列還蠻不實際的，反而轉成字串更快、更直觀。

用 `to_string()` 轉成字串後，range-based for loop 遍歷字串第一個出現 6 的字元，改成 9 後直接 break，然後再把改完的字串換成整數，結束。

Solution ( 0 ms ) :

```cpp=
class Solution {
public:
    int maximum69Number (int num) {
        string s = to_string(num);
        for (char& c : s){
            if (c == '6'){
                c = '9';
                break;
            }
        }
        return stoi(s);
    }
};
```

## [1827. Minimum Operations to Make the Array Increasing](https://leetcode.com/problems/minimum-operations-to-make-the-array-increasing/?envType=problem-list-v2&envId=greedy)

difficulty : Easy.

tags : Array, Greedy

題目敘述：

給定一個整數陣列（索引以 0 作為起始點），可任選一個位置的元素，使其增加 1，讓這個陣列成一個嚴格遞增的陣列。

回傳這樣的最小操作次數。

解題思路：

遍歷 vector，檢查 `nums[i] <= nums[i - 1]`，若成立，算出這兩者的增加量：`nums[i - 1] + 1 - nums[i]`，為什麼要算呢？因為這是要拿去判斷有多少操作次數的，所以之後要再把 `operations` 次數加上這個增加量。

之後就是直接做遞增的動作了。

Solution ( 10 ms ) : 

```cpp=
class Solution {
public:
    int minOperations(vector<int>& nums) {
        int operations = 0;
        for (int i = 1; i < nums.size(); i++){
            if (nums[i] <= nums[i-1]){
                int temp = nums[i - 1] + 1 - nums[i];
                operations += temp;
                nums[i] = nums[i - 1] + 1;
            }
        }
        return operations;
    }
};
```

## [561. Array Partition](https://leetcode.com/problems/array-partition/?envType=problem-list-v2&envId=greedy)

這題真的簡單到哭...害我以為真的就這樣嗎？

difficulty : Easy.

tags : Array, Greedy, Sorting, Counting Sort

題目敘述：

給定一個包含 2n 個整數的整數陣列 nums，將這些整數分組為 n 對 `(a1, b1), (a2, b2), ..., (an, bn)`，使得所有 i 的 `min(ai, bi)` 總和最大化。回傳最大化的和。

解題思路：

排序，然後 for 的遞增條件改成 `i += 2`，`sum += nums[i];` 結束。

Solution ( 15 ms )：

註：這個速度蠻讓人好奇的，我的寫法跟 0ms 完全一樣啊？？

```cpp=
class Solution {
public:
    int arrayPairSum(vector<int>& nums) {
        sort(nums.begin(), nums.end());
        int sum = 0;
        for (int i = 0; i < nums.size(); i += 2){
            sum += nums[i];
        }
        return sum;
    }
};
```

## [2656. Maximum Sum With Exactly K Elements](https://leetcode.com/problems/maximum-sum-with-exactly-k-elements/?envType=problem-list-v2&envId=greedy)

difficulty : Easy.

tags : Array, Greedy

題目敘述：

給定一個索引為 0 作為起始點的整數陣列 nums 和一個整數 k。你的任務是執行以下操作 k 次，來最大化你的分數：

1. 從 nums 選擇一個元素 m。
2. 將所選的 m 從陣列中移除。
3. 新增一個新元素到陣列裡面，其值為 m + 1。
4. 分數增加為 m。

回傳執行該操作恰好 k 次後可獲得的最高分數。

解題思路：

我不確定該題的陣列是否都排序好，保險起見可以用 `max_element(first, last)` 求最大值。

由於每次更新時都是 m + 1，所以也就成了公差為 1 的等差級數。

公式：

 $$S_n = \frac{(a_1 + a_n) \times n}{2}$$
 
所以解題思路就是代公式，結束。

Solution ( 0ms ) : 

```cpp=
class Solution {
public:
    int maximizeSum(vector<int>& nums, int k) {
        int m = *max_element(nums.begin(), nums.end());
        return (m + m + k - 1) * k / 2; // k 是項數，記得分子那邊要減個 1。
    }
};
```

## [2697. Lexicographically Smallest Palindrome](https://leetcode.com/problems/lexicographically-smallest-palindrome/description/?envType=problem-list-v2&envId=greedy)

difficulty : Easy.

tags : Two pointers, String, Greedy

題目敘述：

給定一個由小寫英文字母組成的字串 `s`，你可以多次將其中一個字元替換成另一個小寫字母。

請用最少的操作次數將 `s` 轉換成回文。若有多種解法，請回傳字典序最小的那一個回文字串。

回傳轉換後的回文字串。

解題思路：

使用雙指標 left, right，根據回文特性，若左右兩邊字元不相等，那就繼續下一個判斷條件（題目要求字典序最小）判斷字典序（`s[left] < s[right]` 或 `s[left] > s[right]`），去做相對應的字元賦值。

Solution ( 0ms ) : 

```cpp=
class Solution {
public:
    string makeSmallestPalindrome(string s) {
        int left = 0, right = (int)s.length() - 1;
        while (left < right){
            if (s[left] != s[right]){
                s[left] = s[right] = (s[left] < s[right]) ? s[left] : s[right];
            }
            left++;
            right--;
        }
        return s;
    }
};
```

