置頂

我的 VPython 教學文件 (HackMD 版本)

VPython 教學文件目錄 安裝及測試 基本語法 等速度直線運動 自由落下 終端速度 水平抛射 使用For迴圈計算水平抛射資料 斜向抛射 圓周運動 簡諧運動 單擺 木塊彈簧系統分離 重力及簡諧 行星運動 相疊木塊 雙重簡諧運動 一維彈性碰撞 ...

熱門文章

2026年7月30日 星期四

LeetCode 解題筆記:3014. Minimum Number of Pushes to Type Word I

作者:王一哲
日期:2026年7月30日


LeetCode 題目連結:3014. Minimum Number of Pushes to Type Word I

解題想法


簡單題。題目給一個字串 $word$,仿照用電話按鈕輸入字母的方式,但可以重新分配數字按鈕對應的字母,要計算輸入入 $word$ 至少要按幾下。共有 8 個按鈕可以對應到字母,如果 $word$ 的長度 $n \leq 8$,可以將 $n$ 個字母分配給不同的按鈕,各按 1 下即可;如果 $n > 8$,先處理 8 個字母,$n$ 更新為 $n-8$,下一步最多處理 8 個字母,各按 2 下即可輸入;重複以上的過程直到沒有字母需要輸入為止。

Python 程式碼


Runtime: 0 ms, beats 100.00%. Memory: 19.18 MB, beats 83.33%.
class Solution:
    def minimumPushes(self, word: str) -> int:
        n = len(word)  # 字串長度
        ans, cof = 0, 1  # 答案,要按幾下才能輸入一個字母
        while n > 0:
            if n > 8:  # 剩下超過 8 個字母
                ans += 8 * cof  # 答案加上 8 * cof
                cof += 1  # cof 加 1
                n -= 8  # 字母數量減 8
            else:  # 剩下不到 8 個字母
                ans += n * cof  # 答案加上 n * cof
                n = 0  # 歸零
        return ans


2026年7月29日 星期三

LeetCode 解題筆記:6. Zigzag Conversion

作者:王一哲
日期:2026年7月29日


LeetCode 題目連結:6. Zigzag Conversion

解題想法


中等難度題。題目給一個字串 $s$、列數 $numRows$,要找出共有 $numRows$ 列的之字形排列字串。我先用一個 $numRows$ 列的陣列儲存每一列的字串內容,最後再把陣列內容接成一個很長的字串後回傳,主要的工作是在計算目前這個字元應該填在陣列中的哪一列。

Python 程式碼


Runtime: 7 ms, beats 84.25%. Memory: 19.24 MB, beats 79.60%.
class Solution:
    def convert(self, s: str, numRows: int) -> str:
        # 特例,只有一列,直接輸出 s
        if numRows == 1: return s
        # 一般狀況
        n = len(s)  # 長度
        grid = [""] * numRows  # 儲存答案用的串列
        r, d = 0, 0  # 目前所在的列,方向
        for ch in s:  # 依序讀取字元
            grid[r] += ch  # 加入字元 ch
            if d == 0:  # 向下移動
                r += 1
                if r == numRows - 1: d = 1  # 走到最下方,改成向上走
            else:  # 向上移動
                r -= 1
                if r == 0: d = 0  # 走到最上方,改成向下走
        # 從 grid 讀取字串,組合成字串 t 再回傳
        return "".join(grid)


2026年7月28日 星期二

LeetCode 解題筆記:3517. Smallest Palindromic Rearrangement I

作者:王一哲
日期:2026年7月28日


LeetCode 題目連結:3517. Smallest Palindromic Rearrangement I

解題想法


中等難度題,題目給一個迴文字串 $s$,要將 $s$ 重新排列成字典序最小的迴文字串。我一開始想到的寫法,是先計算各個字母的數量,如果字串 $s$ 長度 $n$ 為奇數,則所有的字母之中只有一個字母的數量是奇數。接下來依照字典序及數量産生需要使用的字母,開一個長度為 $n$ 的串列 $arr$ 儲存答案,由串列兩端向中央依序填入字母。如果 $n$ 是奇數,則 $arr$ 中央再填入唯一的奇數數量字母。最後將 $arr$ 組成字串後回傳。不過這樣寫實在太慢。

後來想到題目給的字串 $s$ 本身就是迴文字串,只要取 $s$ 的左半邊子字串 $left$ 再排序,答案的右半邊 $right$ 就是 $left$ 反序。如果 $s$ 的長度 $n$ 是奇數,$left$ 及 $right$ 之中再加上 $s[n/2]$ 即可。這個寫法的速度快很多。

Python 程式碼


Runtime: 375 ms, beats 21.66%. Memory: 22.32 MB, beats 5.07%.
class Solution:
    def smallestPalindrome(self, s: str) -> str:
        n = len(s)
        cnt = Counter(s)
        chars = []
        odd = ""  # 奇數數量字母
        # 依照字母順序取出數量為偶數的字母
        for ch, val in sorted(cnt.items()):
            if val % 2 == 1:
                chars += [ch] * (val - 1)
                odd = ch
            else:
                chars += [ch] * val
        # 由兩側向中央填入字母
        arr = [""] * n
        for i in range(n//2):
            arr[i] = arr[n-i-1] = chars[i*2]
        # 奇數長度,中間放唯一一個奇數數量的字母
        if n%2 == 1:  
            arr[n//2] = odd
        # 組成字串再回傳
        return "".join(arr)


Runtime: 247 ms, beats 59.91%. Memory: 20.66 MB, beats 91.71%.
class Solution:
    def smallestPalindrome(self, s: str) -> str:
        n = len(s)
        left = "".join(sorted(s[:n//2]))  # 取左半邊字母並排序
        if n%2 == 1:  # 奇數長度
            return left + s[n//2] + left[::-1]  # 右半邊字母為左半邊字母反序,加上中間的字母
        else:
            return left + left[::-1]  # 右半邊字母為左半邊字母反序


2026年7月27日 星期一

LeetCode 解題筆記:1464. Maximum Product of Two Elements in an Array

作者:王一哲
日期:2026年7月17日


LeetCode 題目連結:1464. Maximum Product of Two Elements in an Array

解題想法


簡單題。題目給一個陣列 $nums$,取出其中 2 個數字 $nums[i], nums[j]$,回傳 $(nums[i] - 1) \times (nums[j] - 1)$ 的最大值。由於這題的數值範圍是 $1 \leq nums[i] \leq 1000$,不需要考慮兩個負數相乘的狀況,只要用一個 for 迴圈掃過 $nums$,取出 2 個最大的數字 $a, b$,回傳 $(a-1) \times (b-1)$ 即可。

Python 程式碼


Runtime: 0 ms, beats 100.00%. Memory: 19.20 MB, beats 68.04%.
class Solution:
    def maxProduct(self, nums: List[int]) -> int:
        a, b = -1, -1
        for num in nums:
            if num > a:
                a, b = num, a
            elif num > b:
                b = num
        return (a-1) * (b-1)


2026年7月26日 星期日

LeetCode 解題筆記:628. Maximum Product of Three Numbers

作者:王一哲
日期:2026年7月26日


LeetCode 題目連結:628. Maximum Product of Three Numbers

解題想法


簡單題。題目給一個陣列 $nums$,且 $-1000 \leq nums[i] \leq 1000$,從 $nums$ 之中選取 3 個數字相乘,回傳乘積最大值。先將 $nums$ 由小到大排序,答案可能是選最大的 3 個正整數相乘,或是選 1 個最大的正整數及2 個最小的負整數相乘,回傳兩種選擇的最大值。但是排序的時間複雜度為 $O(n \log n)$,如果想要將時間複雜度降到 $O(n)$ 就不能排序,改用 for 迴圈掃過 $nums$,用 if 更新最大的 3 個數字及最小的 2 個數字,最後再計算乘積最大值。

Python 程式碼


排序。Runtime: 19 ms, beats 64.08%. Memory: 20.50 MB, beats 17.11%.
class Solution:
    def maximumProduct(self, nums: List[int]) -> int:
        nums.sort()
        n = len(nums)
        return max(nums[n-1] * nums[n-2] * nums[n-3], nums[0] * nums[1] * nums[-1])

for 迴圈。Runtime: 4 ms, beats 95.92%. Memory: 20.28 MB, beats 78.13%.
class Solution:
    def maximumProduct(self, nums: List[int]) -> int:
        a = b = c = float('-inf')  # 最大的 3 個數字
        d = e = float('inf')  # 最小的 2 個數字
        for num in nums:
            if num >= a:  # 新的最大值
                a, b, c = num, a, b
            elif num >= b:  # 新的第二大
                b, c = num, b
            elif num > c:  # 新的第三大
                c = num
            if num <= e:  # 新的最小值
                e, d = num, e
            elif num < d:  # 新的第二小
                d = num
        return max(a*b*c, a*d*e)


2026年7月25日 星期六

LeetCode 解題筆記:3536. Maximum Product of Two Digits

作者:王一哲
日期:2026年7月25日


LeetCode 題目連結:3536. Maximum Product of Two Digits

解題想法


簡單題。題目給一個數字 $n$,取出 $n$ 之中任意兩個數字相乘,回傳乘積最大值。基本上就是要找出最大的兩個數字相乘,我是用變數 $a$ 儲存最大的數字,變數 $b$ 儲存第二大的數字,用一個 while 迴圈檢查 $n$ 的每個數字,找出 $a, b$ 的乘,最後回傳 $a \times b$。

Python 程式碼


Runtime: 0 ms, beats 100.00%. Memory: 19.40 MB, beats 22.61%.
class Solution:
    def maxProduct(self, n: int) -> int:
        a, b = 0, 0  # 最大、第二大的數字
        while n > 0:
            d = n % 10
            n //= 10
            if d > a:  # 新的最大值
                a, b = d, a
            elif d > b:  # 新的第二大
                b = d
        return a*b


2026年7月24日 星期五

LeetCode 解題筆記:3514. Number of Unique XOR Triplets II

作者:王一哲
日期:2026年7月24日


LeetCode 題目連結:3514. Number of Unique XOR Triplets II

解題想法


中等難度題。題目給一個陣列 $nums$,要找出從 $nums$ 之中任意取 3 個數字計算 XOR 的結果共有幾個,取的數字可以重複。由於答案只要不重複的計算結果數量,很適合用集合儲存計算結果。這題基本上就是硬算,大約分成以下的步驟:
  1. 將 $nums$ 轉成集合,移除重複的數字,存入 uni_nums。
  2. 由 uni_nums 任意取兩個數字計算 XOR,存入 uni_pairs。
  3. 由 uni_pairs 取一個數字,由 uni_nums 取一個數字,計算 XOR,存入 uni_triplets。
  4. 回傳 uni_triplets 的長度。


Python 程式碼


Runtime: 5873 ms, beats 64.81%. Memory: 19.72 MB, beats 22.22%.
class Solution:
    def uniqueXorTriplets(self, nums: List[int]) -> int:
        uni_nums = set(nums)  # 不重複的數字
        # 由提示2、3,任意選兩個數字計算 XOR
        uni_pairs = {x^y for x in uni_nums for y in uni_nums}
        # 取出 uni_pairs 之中一個數字與 uni_nums 之中一個數字計算 XOR
        uni_triplets = {p^z for p in uni_pairs for z in uni_nums}
        # 回傳答案
        return len(uni_triplets)

Runtime: 6679 ms, beats 61.11%. Memory: 19.70 MB, beats 46.30%.
class Solution:
    def uniqueXorTriplets(self, nums: List[int]) -> int:
        uni_nums = set(nums)  # 不重複的數字
        # 由提示2、3,任意選兩個數字計算 XOR
        uni_pairs = set()
        for y in uni_nums:
            for x in uni_nums:
                uni_pairs.add(x^y)
        # 取出 uni_pairs 之中一個數字與 uni_nums 之中一個數字計算 XOR
        uni_triplets = set()
        for p in uni_pairs:
            for z in uni_nums:
                uni_triplets.add(p^z)
        # 回傳答案
        return len(uni_triplets)


2026年7月23日 星期四

LeetCode 解題筆記:3513. Number of Unique XOR Triplets I

作者:王一哲
日期:2026年7月23日


LeetCode 題目連結:3513. Number of Unique XOR Triplets I

解題想法


中等難度題。這題考數學,題目給一個長度為 $n$ 的陣列 $nums$,且 $nums$ 的內容為任意排列的 $1$ 到 $n$,可以從 $nums$ 之中任取 3 個數字求 XOR,數字可以重複,求總共有幾個計算結果。這題如果用 3 層迴圈硬算一定會超時,要找出數學關係後直接輸出答案。如果 $n = 1$,只有 1 個計算結果 1^1^1 = 1。如果 $n = 2$,只有 2 個計算結果,例如 01^01^01 = 01, 01^01^10 = 10。如果 $n = 3$,最大值為 001^001^111 = 111,不可能超過 $111_2 = 8$,計算結果在 $0$ 到 $2^n - 1$ 之間,答案等於 $2^n$。

Python 程式碼


Runtime: 0 ms, beats 100.00%. Memory: 31.84 MB, beats 91.53%.
class Solution:
    def uniqueXorTriplets(self, nums: List[int]) -> int:
        n = len(nums)
        # 特例,n = 1,1位數,只有 1^1^1 = 1
        if n == 1: return 1
        # 特例,n = 2,2位數,只有 01^01^01 = 1, 01^01^10 = 2
        if n == 2: return 2
        # 一般狀況,n >= 3,最大值為 n 個 1,即 2**n - 1,共有 2**n 個答案
        bits = n.bit_length()
        return 1 << bits


2026年7月22日 星期三

LeetCode 解題筆記:5. Longest Palindromic Substring

作者:王一哲
日期:2026年7月17日


LeetCode 題目連結:5. Longest Palindromic Substring

解題想法


中等難度題。題目給一個字串 $s$,要找出 $s$ 之中最長迴文子字串長度。這題我是用暴力解,先在 $s$ 兩端加上不可能出現的字元當作邊界,再分成奇數長度、偶數長度的子字串各處理一次。用一個 for 迴圈列舉所有可能的中心點索引值,如果是奇數長度中心點為 $c = 1$ 到 $c = len(s) - 2$,如果是偶數長度中心點為 $c = 1$ 到 $c = len(s) - 3$;再用一個 while 迴圈由 $c$ 向兩側延伸,如果兩側的字元相同,可以組長更長的迴文子字串,繼續向外延伸;當 while 迴圈結束時,更新答案。速度比想像中快很多。

Python 程式碼


Runtime: 155 ms, beats 96.12%. Memory: 19.18 MB, beats 91.25%.
class Solution:
    def longestPalindrome(self, s: str) -> str:
        s = '[' + s + ']'  # 兩端加上不可能出現的字元當作邊界
        # 處理奇數長度的字串,c 為中心點,r 為位移量值,檢查範圍為 s[c-r] ~ s[c+r]
        longest = ""  # 最長字串,預設為空字串
        for c in range(1, len(s)-1):  # 依序檢查 c = 1 ~ len(s)-2,要扣掉另外加上去的 []
            r = 1
            while s[c-r] == s[c+r]: r += 1  # 結束時 r 多加 1,回文字串長度為 2*(r-1)+1 = 2*r -1
            if r+r-1 > len(longest):  # 如果新找到的回文字串較長
                longest = s[c-r+1:c+r]
        # 處理偶數長度的字串,i 為中心點,r 為位移量值,檢查範圍為 s[i-r] ~ s[i+r+1]
        for i in range(1, len(s)-2):  # 依序檢查 i = 1 ~ len(s)-3,要扣掉另外加上去的 []
            r = 0
            while s[i-r] == s[i+r+1]: r += 1  # 結束時回文字串長度為 2*r
            if r+r > len(longest):
                longest = s[i-r+1:i+r+1]
        return longest


2026年7月21日 星期二

LeetCode 解題筆記:3499. Maximize Active Section with Trade I

作者:王一哲
日期:2026年7月21日


LeetCode 題目連結:3499. Maximize Active Section with Trade I

解題想法


中等難度題,題目給一個只包含 0、1 的字串 $s$,可以對 $s$ 操作 1 次,過程為
  1. 取一段連續的 1,其兩側皆為連續的 0,將中間的 1 全部改成 0。
  2. 再將上個步驟取出的 3 段都改成 1。
題目要計算操作後 $s$ 之中最多可以有幾個 1。因為以上的操作並不會讓原來的 1 消失,反而是兩側的 0 變成 1,如果要使操作後的 1 數量最多,就是要找出兩段 0 數量相加的最大值。解題時先依照題義補上兩側的 1,儲存成新的字串 $t$。接下來計算連續出現的 0, 1 長度,儲存至串列 $rle$。最後找出最大增益,取連續兩段 0 的總長度最大值 $imax$,回傳 $s$ 之中 1 的數量加上 $imax$。

Python 程式碼


Runtime: 561 ms, beats 85.98%. Memory: 21.08 MB, beats 61.68%.
class Solution:
    def maxActiveSectionsAfterTrade(self, s: str) -> int:
        t = "1" + s + "1"  # 依照題義補上兩側的 1
        n = len(t)  # 長度,s 的內容為 1 ~ n-2
        
        # --- 計算連續出現的 0, 1 長度 ---
        rle = []  # 遊程編碼,run-length encoding
        curr = '1'  # 目前的字元,最左側是 1
        cnt = 1  # 數量
        for i in range(1, n):  # 掃過字串 t
            if t[i] == curr:  # 相同的字元
                cnt += 1  # 數量加 1
            else:  # 不同的字元,結算前一段
                rle.append(cnt)
                curr = t[i]
                cnt = 1
        rle.append(cnt)  # 結算最後一段

        # --- 找出最大增益,取連續兩段 0 的總長度最大值 ---
        imax, m = 0, len(rle)  # 最大值,rle 長度
        for i in range(2, m-2, 2):  # i 只找 1 所在的位置,排除兩端
            imax = max(imax, rle[i-1] + rle[i+1])
        # 答案為 s 之中 1 的數量加上 imax
        return s.count('1') + imax