iT邦幫忙

2022 iThome 鐵人賽

DAY 8
0
自我挑戰組

leetcode 30天 不中斷解題挑戰系列 第 8

Day8 leetcode 隨機挑題(String, Greedy, Linked List)

  • 分享至 

  • xImage
  •  

首先是 557. Reverse Words in a String III (easy)
https://leetcode.com/problems/reverse-words-in-a-string-iii/

題目要求很簡單,會給一個串列s,裡面有很多單字,字與字之間有一格空格。要把每個單字都進行翻轉。

雖然標籤有two pointer,但python做這題用pointer反而覺得有點矯情。
就簡單用個split() + [::-1]就解決了

class Solution:
    def reverseWords(self, s: str) -> str:
        s = s.split(" ")
        for i in range(len(s)):
            s[i] = s[i][::-1]
        return " ".join(s)

再來是 121. Best Time to Buy and Sell Stock (easy)
https://leetcode.com/problems/best-time-to-buy-and-sell-stock

這題題目會給一個叫做price的list,裡面所存的數字可以當作是某項物品的價位。
當只能買賣一次時,能夠賺取的最大金額為多少(買的日期一定要比賣的日期早)

像這種題目首先要試的方法當然就是暴力法:
兩層for迴圈,把後面所有的數字都減過一遍,找最小值直接取絕對值就結束了。

class Solution:
    def maxProfit(self, price: List[int]) -> int:
        #這樣寫果然會TLE
        ansList = [0]
        for i in range(len(prices)):
            for j in range(i+1,len(prices)):
                temp = prices[i] - prices[j]
                if temp < 0:
                    ansList.append(temp)
        ans = min(ansList)
        return abs(ans)

那像這種毫無效率的方法會TLE就不意外。
因此接下來改成以下的作法

  1. 製造兩個pointer front,back,一個指著要買的數字,一個指要賣的數字
  2. 透過while迴圈一前一後往後比較
  3. 當back指著的數字小於front時,front馬上指到back的位置上同時back向下一格指
  4. 當back指著的數字大於front時,儲存該筆買賣紀錄,同時back繼續向下一格指
class Solution:
        #這題是用兩個pointer沒有錯,從前往後
        ansList = [0]
        front ,back = 0, 1
        while back<len(price):
            if price[front] >= price[back]:
                front = back
                back +=1
                
            else:
                ansList.append(price[back] - price[front])
                back +=1
        ans = max(ansList)
        return ans

接下來是 409. Longest Palindrome (easy)
https://leetcode.com/problems/longest-palindrome

這題會給一個字串s,要從這s裡面拼湊出回文字串,並且找出最長的長度。

想法:

  1. 透過Counter找出每個字的個數有多少個
  2. 把所有數字相加
  3. 因為每個回文最多可以容納一個奇數,所以超過一個奇數的話,每多一個長度要少一
class Solution:
    #別忽略了可以是多個奇數的狀況ex:3個a、5個b
    #別忘記一件事情奇數個東西也可以變成偶數阿-1就好
    #簡單來說我只要計算有多少個奇數就好假設有3個奇數就總字數-2,n個奇數就總字數-(n-1)
    def longestPalindrome(self, s: str) -> int:
        sDict = Counter(s)
        # print(sDict)
        count = 0
        flag = 0 
        for i in sDict.values():
            if i % 2:
                flag = 1
                count += i-1
            else:
                count += i
        if flag:
            return count+1
        return count

這是一開始的想法,但這樣寫其實有幾個問題

  1. 為什麼不用減的就好
  2. 迴圈裡面一直有運算效率會降低
    所以又改成以下方法
class Solution:
    #別忽略了可以是多個奇數的狀況ex:3個a、5個b
    #別忘記一件事情奇數個東西也可以變成偶數阿-1就好
    #簡單來說我只要計算有多少個奇數就好假設有3個奇數就總字數-2,n個奇數就總字數-(n-1)
    def longestPalindrome(self, s: str) -> int:
        sDict = Counter(s)
        flag = 0
        for i in sDict.values():
            if i % 2:
                flag += 1
        if flag:
            return len(s) - flag + 1
        else:
            return len(s)

相對而言簡單很多,指需要統計奇數有多少個,超過一個的話扣掉他即可。

下一題 142. Linked List Cycle II (medium)
https://leetcode.com/problems/linked-list-cycle-ii/
需要思考一下的題目
要求找出這個linked list是否cycle,以及從哪個node開始cycle

https://ithelp.ithome.com.tw/upload/images/20220922/20108649uSEHYyEleQ.png
由圖可知,從back走了A+B到撞擊點,也就是說front要走2A+2B-1若中間跑loop跑了n圈,距離為nL,則可以這樣說 A+B+nL = 2A+2B-1 -> A+B-1 = nL 我們要找的A就是nL-B+1,那因為跟跑操場一樣,每圈長度固定,所以可以簡寫為L-B+1。
所以首先第一步,使用Floyd確定是否為cycle後
第二步就是back跟head一起往前L-B步即可,由於front有偷走一步,所以back也要先走一步把那個+1去掉。
所以會變成以下的程式碼

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def detectCycle(self, head: Optional[ListNode]) -> Optional[ListNode]:
        #龜兔賽跑檢查是否為cycle
        if head is None or head.next is None:
            return None
        back = head
        front = head.next
        flag = 0
        while front:
            if flag:
                back = back.next
                flag = 0
                front = front.next
                if front == back:
                    break
            else:
                front = front.next
                flag = 1
        else:
            return None
        #尋找重複開始的地方
        back = back.next
        while head != back:
            head = head.next
            back = back.next
        return head
    

稍微參考一下別人的想法以及簡化,程式碼又可以變成如下:

class Solution:
    def detectCycle(self, head: Optional[ListNode]) -> Optional[ListNode]:
        back,front = head,head
        while front and front.next:
            front = front.next.next
            back = back.next
            if back == front:
                while head != back:
                    head = head.next
                    back = back.next
                return head
        return None

上一篇
Day7 leetcode 隨機挑題 (鏈結串列、Simulation)
下一篇
Day9 leetcode 解題挑戰(Tree,Binary Search)
系列文
leetcode 30天 不中斷解題挑戰30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言