iT邦幫忙

2024 iThome 鐵人賽

DAY 3
0
自我挑戰組

LeetCode 自我修煉馬拉松系列 第 3

Day3: Easy 4-5

  • 分享至 

  • xImage
  •  

今天的題單:

  • Best Time to Buy and Sell Stock

  • Valid Palindrome

121. Best Time to Buy and Sell Stock

一開始寫了 O(n^2) time brute force 解,比對每兩天的差值。

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

在想 O(n) 解法的時候卡了很久,參考了別人的方法才想通。

我原本的思路:

從第一天開始往後看,遇到 local min 記起來後繼續往後看,遇到 local max 後計算獲利。之後在遇到 local min 需要更新最低點紀錄,再往後看遇到 local max 計算獲利,如此往復。

這裡卡住的點在:

如果前一個低點比後一個低點低,這樣最低點被更新後,會不會漏掉最大獲利?

在參考了別人的解法後,發現思路方向大致是對的,差了一點點:

從第一天開始往後看,遇到 local min 記起來後繼續往後看,遇到 local max 後計算獲利。之後在遇到更低的 local min 需要更新最低點紀錄,再往後看遇到 local max 計算獲利,如此往復。

用後者思路來分析,假設有兩個低點:

  • 前一個較高,後一個較低

    • 遇到後一個低點會更新最低買進點,之後的獲利會用新的最低點算。

    • 獲利大於歷史最大獲利才會更新

  • 前一個較低,後一個較高

    這裡產生一個直覺問題:我需要去記住前一個低點,才不會漏掉最大獲利。這也就是原本卡住的地方。但是其實最低買進點只會在遇到更低點的時候更新,所以計算獲利時會是用前一個低點算,所以漏掉的狀況不會發生

// O(n) solution
class Solution {
public:
    // no profit: profit <= 0
    int maxProfit(vector<int>& prices) {

        int min_price = 10000;
        int max_profit = 0;

        for (int i=0; i<prices.size(); i++) {
            // find the min price
            if (prices[i] < min_price) {
                min_price = prices[i];
            }

            if ((prices[i] - min_price) > max_profit) {
                max_profit = prices[i] - min_price;
            }

        }
        return max_profit;
    }
};

125. Valid Palindrome

判斷一個句子去掉非字母數字(non-alphanumeric)字符剩下的部分是不是回文。

Non-alphanumeric characters refer to those characters that are neither alphabets (a-z) nor numbers(0-9)

解法很單純,只要去掉字母數字以外的字符再判斷是不是回文就好了。判斷回文可以用 two pointer 的方法,從兩端一個一個字比對到中間看有沒有都一樣即可。

需要處理的事有兩件:一是去除 non-alphanumeric 字符的部分,二是大寫轉小寫。

本來想說要用 ascii code 編碼去判斷,沒想到發現有 isalnum()tolower() 這個函數可以用!省下很多工夫。

class Solution {
public:
    bool isPalindrome(string s) {
        // A-Z: 65 - 90
        // a-z: 97 - 122
        // 0-9: 48 - 57
        
        string new_s = s;
        
        // news_s.lower()
        for (string::iterator it=new_s.begin(); it!=new_s.end();) {
            if (*it >= 65 && *it <= 90)
                *it += 32;
            // remove non-alphanumeric characters
            if (!isalnum(*it)) {
                it = new_s.erase(it);
            } else {
                it++;
            }
        }

        // check if s is palindrome by two pointer

        string::iterator left = new_s.begin();
        string::iterator right = new_s.end();

        right--;

        int len = new_s.size();

        if (len <= 1)
            return true;

        if (len % 2 == 1) { // the length of the string is odd
            while (left != right) {
                if (*left != *right)
                    return false;
                left++;
                right--;
            }
            return true;
        } else { // the length of the string is odd even
            while (right-left != 1) {
                if (*left != *right)
                    return false;
                left++;
                right--;
            }
            if (*left != *right)
                return false;
            else
                return true;
        }
    }
};

提交之後發現速度比較慢,參考了較快的 sample code

  • 直接在檢查時跳過非字母數字字符速度會比較快一些。

  • 原本寫法依據長度把奇數和偶數分開處理,可以迴圈條件的部分改成 left <= right 簡化實作。

class Solution {
public:
    bool isPalindrome(string s) {
        // A-Z: 65 - 90
        // a-z: 97 - 122
        // 0-9: 48 - 57

        int left = 0;
        int right = s.size() - 1;

        while (left <= right) {
            if (!isalnum(s[left])) {
                left++;
                continue;
            }
            if (!isalnum(s[right])) {
                right--;
                continue;
            }
            if (tolower(s[left]) != tolower(s[right])) {
                return false;
            }
            left++;
            right--;
        }
        return true;
    }
};

上一篇
Day2: Easy 1-3
下一篇
Day4: Easy 6-8
系列文
LeetCode 自我修煉馬拉松30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言