演算法與資料結構
  • 簡介
  • 前言
    • 事前準備
    • 資料結構場景
    • 複雜度分析
      • 時間複雜度
      • 空間複雜度
  • 分類題型
    • Array 陣列
      • 88. Merge Sorted Array
      • 1089. Duplicate Zeros
      • 941. Valid Mountain Array
      • 1710. Maximum Units on a Truck
      • 54. Spiral Matrix
      • 73. Set Matrix Zeroes
      • 498. Diagonal Traverse
      • 238. Product of Array Except Self
      • HackerRank Counting Valleys
      • 1089. Duplicate Zeros
    • Backtrack 回溯法
      • 51. & 52. N Queens
      • 37. Sudoku Solver
      • 77. Combinations
      • 39. Combination Sum
        • 40. Combination Sum II
        • 216. Combination Sum III
      • 78. Subsets
        • 90. Subsets II
      • 46. Permutations
        • 47. Permutations II
      • 22. Generate Parentheses
      • 1087. Brace Expansion
      • 332. Reconstruct Itinerary
      • 489. Robot Room Cleaner
      • 17. Letter Combinations of a Phone Number
      • 79. Word Search
        • 212. Word Search II
      • 425. Word Squares
      • 1219. Path with Maximum Gold
      • 247. Strobogrammatic Number II
    • Binary Search 二分搜索
      • Rotated Array 旋轉陣列問題
        • 33. Search in Rotated Sorted Array
        • 81. Search in Rotated Sorted Array II
        • 153. Find Minimum in Rotated Sorted Array
        • 154. Find Minimum in Rotated Sorted Array II
      • 374. Guess Number Higher or Lower
      • 704. Binary Search
      • 34. Find First and Last Position of Element in Sorted Array
      • 69. Sqrt(x)
      • 367. Valid Perfect Square
      • 374. Guess Number Higher or Lower
      • 278. First Bad Version
      • 162. Find Peak Element
      • 852. Peak Index in a Mountain Array
      • 35. Search Insert Position
      • 875. Koko Eating Bananas
      • 1011. Capacity To Ship Packages Within D Days
      • 173. Binary Search Tree Iterator
      • 1586. Binary Search Tree Iterator II
    • Dynamic Programming 動態規劃
      • 509. Fibonacci Number
      • 70. Climbing Stairs
      • 55. Jump Game
      • 62. Unique Paths
      • 64. Minimum Path Sum
      • 174. Dungeon Game
      • 91. Decode Ways
      • 72. Edit Distance
      • 221. Maximal Square
      • 329. Longest Increasing Path in a Matrix
      • 198. House Robber
        • 213. House Robber II
      • 1109. Corporate Flight Bookings
      • 983. Minimum Cost For Tickets
      • 1143. Longest Common Subsequence
        • 583. Delete Operation for Two Strings
        • 712. Minimum ASCII Delete Sum for Two Strings
      • 53. Maximum Subarray
      • 152. Maximum Product Subarray
      • 975. Odd Even Jump
      • 115. Distinct Subsequences
      • 416. Partition Equal Subset Sum
      • 10. Regular Expression Matching
      • 651. 4 Keys Keyboard
    • Hash Table/Set 雜湊表
      • 242. Valid Anagram
      • 49. Group Anagrams
      • 217. Contains Duplicate
        • 219. Contains Duplicate II
        • 220. Contains Duplicate III
      • 187. Repeated DNA Sequences
      • 1170. Compare Strings by Frequency of the Smallest Character
      • 448. Find All Numbers Disappeared in an Array
      • 560. Subarray Sum Equals K
      • 1010. Pairs of Songs With Total Durations Divisible by 60
    • Heap 堆
      • 347. Top K Frequent Elements
      • 692. Top K Frequent Words
      • 973. K Closest Points to Origin
      • 128. Longest Consecutive Sequence
      • 1167. Minimum Cost to Connect Sticks
    • Linked List 鏈結串列
      • 876. Middle of the Linked List
      • 21. Merge Two Sorted Lists
        • 23. Merge k Sorted Lists
      • 148. Sort List
      • 206. Reverse Linked List
        • 92. Reverse Linked List II
    • Stack 棧
      • 20. Valid Parentheses
      • 394. Decode String
      • 84. Largest Rectangle in Histogram
      • 155. Min Stack
    • String 字串
      • 43. Multiply Strings
      • 344. Reverse String
      • 726. Number of Atoms
      • 8. String to Integer (atoi)
      • 12. Integer to Roman
      • 696. Count Binary Substrings
    • Tree 樹
      • Breadth-first search 廣度優先搜索
        • 111. Minimum Depth of Binary Tree
        • 200. Number of Islands
        • 752. Open the Lock
        • 279. Perfect Squares
        • 286. Walls and Gates
        • 417. Pacific Atlantic Water Flow
        • 994. Rotting Oranges
        • 429. N-ary Tree Level Order Traversal
        • 116. Populating Next Right Pointers in Each Node
        • 117. Populating Next Right Pointers in Each Node II
        • 430. Flatten a Multilevel Doubly Linked List
        • 1135. Connecting Cities With Minimum Cost
      • Preorder 前序遍歷
        • 105. Construct Binary Tree from Preorder and Inorder Traversal
        • 144. Binary Tree Preorder Traversal
        • 589. N-ary Tree Preorder Traversal
        • 255. Verify Preorder Sequence in Binary Search Tree
      • Inorder 中序遍歷
        • 94. Binary Tree Inorder Traversal
        • 426. Convert Binary Search Tree to Sorted Doubly Linked List
      • Postorder 後序遍歷
        • 106. Construct Binary Tree from Inorder and Postorder Traversal
        • 145. Binary Tree Postorder Traversal
        • 590. N-ary Tree Postorder Traversal
        • 114. Flatten Binary Tree to Linked List
        • 652. Find Duplicate Subtrees
        • 124. Binary Tree Maximum Path Sum
        • 543. Diameter of Binary Tree
        • 337. House Robber III
      • BST
        • 98. Validate Binary Search Tree
        • 450. Delete Node in a BST
        • 700. Search in a Binary Search Tree
        • 701. Insert into a Binary Search Tree
        • 1373. Maximum Sum BST in Binary Tree
        • 230. Kth Smallest Element in a BST
        • 99. Recover Binary Search Tree
      • Serialization & Deserialization
        • 606. Construct String from Binary Tree
        • 536. Construct Binary Tree from String
        • 297. Serialize and Deserialize Binary Tree
        • 428. Serialize and Deserialize N-ary Tree
      • Graph 圖
        • 1971. Find if Path Exists in Graph
        • 323. Number of Connected Components in an Undirected Graph
        • 547. Number of Provinces
      • 100. Same Tree
        • 572. Subtree of Another Tree
      • 1379. Find a Corresponding Node of a Binary Tree in a Clone of That Tree
      • 226. Invert Binary Tree
      • 104. Maximum Depth of Binary Tree
      • 559. Maximum Depth of N-ary Tree
      • 102. Binary Tree Level Order Traversal
      • 261. Graph Valid Tree
      • 250. Count Univalue Subtrees
      • 222. Count Complete Tree Nodes
      • 112. Path Sum
      • 113. Path Sum II
      • 437. Path Sum III
    • Trie 字典樹
      • 208. Implement Trie (Prefix Tree)
      • 677. Map Sum Pairs
      • 648. Replace Words
      • 588. Design In-Memory File System
      • 642. Design Search Autocomplete System
      • 211. Design Add and Search Words Data Structure
      • 1268. Search Suggestions System
    • Two Pointers 雙指針
      • 977. Squares of a Sorted Array
      • 1095. Find in Mountain Array
      • 27. Remove Element
      • 141. Linked List Cycle
        • 142. Linked List Cycle II
      • 19. Remove Nth Node From End of List
      • 26. Remove Duplicates from Sorted Array
      • 83. Remove Duplicates from Sorted List
      • 283. Move Zeroes
    • Sliding Window 滑動窗口
      • 3. Longest Substring Without Repeating Characters
      • 76. Minimum Window Substring
      • 567. Permutation in String
      • 438. Find All Anagrams in a String
      • 424. Longest Repeating Character Replacement
      • 485. Max Consecutive Ones
      • 1004. Max Consecutive Ones III
      • 904. Fruit Into Baskets
      • 1248. Count Number of Nice Subarrays
      • 1358. Number of Substrings Containing All Three Characters
      • 1234. Replace the Substring for Balanced String
      • 930. Binary Subarrays With Sum
      • 209. Minimum Size Subarray Sum
      • 992. Subarrays with K Different Integers
      • 713. Subarray Product Less Than K
      • 862. Shortest Subarray with Sum at Least K
      • 239. Sliding Window Maximum
      • 159. Longest Substring with At Most Two Distinct Characters
      • 340. Longest Substring with At Most K Distinct Character
      • 992. Subarrays with K Different Integers
    • Bit Manipulation 位元運算
      • 136. Single Number
      • 7. Reverse Integer
      • 191. Number of 1 Bits
    • Math 數學
      • 553. Optimal Division
      • 204. Count Primes
      • 372. Super Pow
      • 829. Consecutive Numbers Sum
      • 1492. The kth Factor of n
    • Other 其他
      • 31. Next Permutation
      • 1446. Consecutive Characters
      • 386. Lexicographical Numbers
      • 269. Alien Dictionary
      • 48. Rotate Image
      • 157. Read N Characters Given Read4
        • 158. Read N Characters Given Read4 II - Call multiple times
      • 246. Strobogrammatic Number
    • Object Oriented Design 物件導向設計
      • 710. Random Pick with Blacklist
      • 380. Insert Delete GetRandom O(1)
      • 271. Encode and Decode Strings
      • 348. Design Tic-Tac-Toe
  • 經典題目
    • Best Time to Buy and Sell Stock 股票買賣問題
      • 121. Best Time to Buy and Sell Stock
      • 122. Best Time to Buy and Sell Stock II
      • 123. Best Time to Buy and Sell Stock III
      • 188. Best Time to Buy and Sell Stock IV
      • 309. Best Time to Buy and Sell Stock with Cool down
      • 714. Best Time to Buy and Sell Stock with Transaction Fee
    • Palindrome 回文
      • 125. Valid Palindrome
      • 680. Valid Palindrome II
      • 266. Palindrome Permutation
      • 9. Palindrome Number
      • 866. Prime Palindrome
      • 5. Longest Palindromic Substring
      • 647. Palindromic Substrings
      • 516. Longest Palindromic Subsequence
      • 1930. Unique Length-3 Palindromic Subsequences
      • 234. Palindrome Linked List
    • Time Intervals 時間區間問題
      • 252. Meeting Rooms
      • 253. Meeting Rooms II
      • 56. Merge Intervals
      • 57. Insert Interval
      • 495. Teemo Attacking
      • 759. Employee Free Time
      • 986. Interval List Intersections
      • 435. Non-overlapping Intervals
      • 452. Minimum Number of Arrows to Burst Balloons
      • 729. My Calendar I
      • 731. My Calendar II
      • 732. My Calendar III
      • 163. Missing Ranges
      • 1024. Video Stitching
    • Calculator 計算機問題
      • 224. Basic Calculator
      • 227. Basic Calculator II
      • 772. Basic Calculator III
    • Add One 加一問題
      • 66. Plus One
      • 67. Add Binary
      • 369. Plus One Linked List
      • 2. Add Two Numbers
        • 445. Add Two Numbers II
      • 989. Add to Array-Form of Integer
    • Clone Graph 複製圖形
      • 133. Clone Graph
      • 1490. Clone N-ary Tree
      • 138. Copy List with Random Pointer
      • 1485. Clone Binary Tree With Random Pointer
    • Cache 快取問題
      • 146. LRU Cache 最久未使用演算法
      • 460. LFU Cache 最近最少使用演算法
    • n Sum 問題
      • 1. 2 Sum
      • 15. 3Sum
      • 18. 4Sum
      • 454. 4 Sum II
      • 167. Two Sum II - Input array is sorted
      • 170. Two Sum III - Data structure design
      • 653. Two Sum IV - Input is a BST
      • 16. 3Sum Closest
      • 259. 3Sum Smaller
      • 16. 3Sum Closest
    • Lowest Common Ancestor of a Binary Tree 最近共同祖先問題
    • The Maze 球滾迷宮問題
      • 490. The Maze
      • 505. The Maze II
    • Find Median 尋找中位數
      • 295. Find Median from Data Stream
      • 4. Median of Two Sorted Arrays
    • Course 課程問題
      • 207. 210. Course Schedule I & II
      • 1136. Parallel Courses
    • Coin Change 零錢問題
      • 322. Coin Change
      • 518. Coin Change 2
    • Binary Indexed Tree 樹狀陣列或二元索引樹
      • 303. Range Sum Query - Immutable
      • 307. Range Sum Query - Mutable
      • 315. Count of Smaller Numbers After Self
    • Longest Increasing Subsequence 最長遞增子序列的問題
      • 300. Longest Increasing Subsequence
      • 354. Russian Doll Envelopes
      • 673. Number of Longest Increasing Subsequence
    • Robot Bounded In Circle 掃地機器人
    • Containing Water 裝水問題
      • 11. Container With Most Water
      • 42. Trapping Rain Water
      • 755. Pour Water
    • Word Ladder 文字梯問題
      • 127. Word Ladder
      • 126. Word Ladder II
    • Egg Drop 高樓扔雞蛋
    • Custom sorting 排序技巧
      • 937. Reorder Data in Log Files
    • Word Break 字串組合問題
      • 139. Word Break
      • 140. Word Break II
      • 472. Concatenated Words
  • 常見演算法
    • Sorting 排序
      • Merge Sort (Accepted)
      • Quick Sort (Accepted)
      • Heap Sort (Accepted)
      • Bubble Sort (TLE)
      • Insertion Sort (TLE)
      • Selection Sort (TLE)
    • Shuffle Array 打亂陣列內的元素
    • 池塘抽樣
      • 382. Linked List Random Node
      • 398. Random Pick Index
  • Python 技巧
    • 陣列複製
    • 矩陣操作
      • 向矩陣中的四個方向移動
      • 矩陣遍歷的方法
Powered by GitBook
On this page
  • 暴力解
  • 動態規劃解
  1. 分類題型
  2. Dynamic Programming 動態規劃

975. Odd Even Jump

Previous152. Maximum Product SubarrayNext115. Distinct Subsequences

Last updated 3 years ago

這一題建議在後面練習的時候再來寫

根據網路上的數據,這一題曾經是 Google 面試的高頻動態規劃題目,LeetCode 的難度是困難的題目,一般而言我刷題的目標都是放在困難度中等的題目,不過有些困難的題目如果不是存在著特殊解法,是很好幫助我們去看看如何把不同的演算法。

這一個題目是問說,有一個陣列,裡面有不同的數字隨機排列,目標是要找出有幾個點可以通過一個特殊的規則跳到終點,也就是陣列中的最後一個位置,特殊的規則如下:

是第**「奇數」次跳躍時,下一次可以跳的點是在當前位置 arr[i] 右側的任意一個位置 j ,只要 j > i 且 arr[j] 的值大於或等於** arr[i] ,如果說有很多地點可以跳,那就選比 arr[i] 還大的值中,最小的那一個點,如果遇上有多個相同的數字,選擇最近的那個跳過去(j最小)。

也就是說要考量的點按照順序如下

  1. j > i

  2. arr[j] >= arr[i]

  3. 滿足以上條件最小的 arr[j]

  4. 滿足以上條件最小的 j

arr = [1, 3, 2, 2]
i = 0 的時候,j = 1, j = 2, j = 3 都符合第二個條件
但是只有 j = 2, = 3 滿足第二個條件
但是要選比較小的 index ,所以只能跳到 2

是第**「偶數」次跳躍時,下一次可以跳的點是在當前位置 arr[i] 右側的任意一個位置 j ,只要 j > i 且 arr[j] 的值小於或等於** arr[i] ,如果說有很多地點可以跳,那就選比 arr[i] 還小的值中,最大的那一個點,如果遇上有多個相同的數字,選擇最近的那個跳過去(j最小)。

考慮的順序同奇數次跳躍

其實光到這一步,要理解整個題目的規則就有點難度了,就網路上分享的經驗中,Google 的確喜歡考這樣的題目,考察面試者的反應與理解題目的思路。

暴力解

這個題目我一開始還是先使用暴力解,我會把我的想法一步一步記錄起來。

我想先解決最簡單的第一個問題,那就是每次我要如何判斷是奇數跳或是偶數跳?這是一個在現實應用中也很常用到的技巧,奇偶變換的問題,其實就是布林值的轉換,我不用確切記得當前的步數是第幾步,我只要知道我目前是在奇數的位置,下一步就一定是偶數。

下面的程式碼完成了主要的概念,我用 curr 記錄目前是從哪個點開始出發,每次跳躍我都會前進一些 index ,一直到如果我可以走到最後,就代表當前的位置 i 存在著路徑可以走到最後一個位置。

class Solution:
    def oddEvenJumps(self, arr: List[int]) -> int:
        ans = 0
        for i in range(len(arr) - 1):
            curr = i 
            isOdd = True
            while curr < len(arr):
                if isOdd:
                    # TODO
                else:
                    # TODO
                isOdd = not isOdd
            if curr == len(arr) - 1:
                # path does exist            
                ans += 1
            else:
                # path doesn't exist
                continue
        return ans

接著要處理題目比較困難的部分了,我一開始想到的直覺方法是直接去掃描整個右半部的陣列,先找出所有大於當前位置的值,然後再找出這些值得最小值,再比較哪個 index 最小,這樣想想其實沒有很好做,我後來就想到了其實我可以直接使用 heap 來處理就好,因為我要找的是最值,沒有排序找最值最好的方法就是用 heap ,加入 heap 的方式很簡單,我只要選擇比當前最大值大的值加入進去就好,也順便把 index 放進去,最後直接取最上面的值,就是最小值了。

這裡要注意的一點是,右半部可能並沒有路徑可以走,那這樣的話就是 heap 會是空值,我會返回 -1 作為,往右前進的索引並不存在。

class Solution:
    def oddEvenJumps(self, arr: List[int]) -> int:

        def oddSearch(curr):
            heap = []
            heapq.heapify(heap)
            for i in range(curr+1, len(arr)):
                if arr[curr] <= arr[i]:
                    heapq.heappush(heap, (arr[i], i))
            if not heap:
                return -1
            else:
                val, index = heapq.heappop(heap)
            return index

        def evenSearch(curr):
            heap = []
            heapq.heapify(heap)
            for i in range(curr+1, len(arr)):
                if arr[curr] >= arr[i]:
                    heapq.heappush(heap, (-arr[i], i))
            if not heap:
                return -1
            else:
                val, index = heapq.heappop(heap)
            return index

        ans = 1
        res = []
        memo = {}
        for i in range(len(arr) - 1):
            curr = i 
            isOdd = True
            while curr < len(arr):
                if isOdd:
                    index = oddSearch(curr)
                    if index == -1:
                        break
                    curr = index
                else:
                    index = evenSearch(curr)
                    if index == -1:
                        break
                    curr = index
                isOdd = not isOdd
            if curr == len(arr) - 1:
                ans += 1
                res.append(i)

        return ans

這樣的時間複雜度是很高的,因為我們至少需要遍歷一次陣列,每次跳躍很不巧的可能只能跳一格,花大約 ~ O(nlogn)O(nlogn)O(nlogn) 的時間處理 Heap ,總共的時間複雜度約是 O(n3logn)O(n^3logn)O(n3logn) 。

動態規劃解

題目做多了,遇到這種邊走邊選擇的題目,很直覺的就可以想到要怎麼用動態規劃解,這一題困難的是在做選擇的時候,需要考慮情境,像是我如果可以到位置 j ,可能是之前的格子在奇數跳的時候跳過來的,也可能是之前的格子,在偶數跳的時候跳過來的,兩種跳法也都不一樣,我一開始在寫的時候也會想,如果要考慮情境的話,還可以用動態規劃來解嗎?因為這樣有重疊子問題嗎?

這個題目一開始我也是寫的時候也是寫不出來,我先參考了別人講解的思考過程後,才嘗試看看要怎麼寫的。

我們先看看能不能先從第一個困難點解決,那就是先解決我們要往哪邊跳,如果可以先算出在奇數時該先跳到哪裡,和偶數時要跳去哪裡,那就會很方便,可以少去每次重新檢查的行為。

建立這個座標的方式滿特別的,首先既然要比大小,所以需要將原先的陣列做排序,可是排序玩原先的位置資訊就不在了,但是偏偏我們要知道他原先的索引,才能知道怎麼做。

這個答案是別人的做法,給我幾天我可能可以想到類似的寫法,面試一個小時的時間我自己是真的做不出來。

stack = []
odd_next_jump = [0] * n

# 將原先陣列的元素與索引一起取出後排序,這樣的排序會有這樣的特性:
# 裡面的元素從小排到大,如果遇上相同的值,就會依照索引由小排到大
for ele, idx in sorted([ele, idx] for idx, ele in enumerate(arr)):
    # 所有已經被放入到 stack 的索引,其索引所對應到的值
    # 一定比我當前索引對應到的值小,所以如果其索引在我左邊(stack[-1] < i)
    # 代表 stack[-1] 目前存的索引,他的下一步會是現在的索引 i 
    while stack and stack[-1] < i:
        # 於是,我們可以把這個記錄起來
        # ex: next_higher[2] = 4 就是代表 idx 2 可以走到 idx 4 
        odd_next_jump[stack.pop()] = i
    stack.append(i)

反之亦然

stack = []
even_next_jump = [0] * n

for ele, idx in sorted([-ele, idx] for idx, ele in enumerate(arr)):
    while stack and stack[-1] < idx:
        even_next_jump[stack.pop()] = i
    stack.append(idx)

最後一步就是要完成動態規劃的部分了。

我們會需要兩個 dp 的陣列,分別是 dp_odd 和 dp_even 這個要記錄的是,每個位置是否可以透過奇數跳或是偶數跳跳過來,這也是最後一個很燒腦的部分。

首先,不管是 dp_odd 或是 dp_even 最後一個位置就是陣列中的最後一個元素,我們都設定是 True 。

dp_odd = [False] * n 
dp_even = [False] * n
dp_odd[-1] = True
dp_even[-1] = True

一直到這個部分比較好理解,接下來最後一個部分就是要透過動態規劃來完成,這裡是一個自底向上的動態規劃,只是這個自底向上的行程是從最後一個位置往前面推,為什麼呢?因為最後一個位置,其實反而是這個題目的 Base Case 。

往前走的方向是這樣判斷的,如果說 dp_odd[i] 能往前走,要看的是之後的 dp_even[k] 是不是可以到的,k 取得的方式是看看 odd_next_jump[i] 能不能到,如果不能到的話就會是 0 ,那 0 又比 i 前面,所以這時候 dp_even[0] 會是 False 這時候 dp_odd[i]就會是 False 。

整個情況其實有點難想,尤其又是從後往前推,我覺得最容易的理解方式是考中斷點,用中斷點來看所有的變數的情況是什麼樣子。

真實面試中的時候,或許我真的天資不夠聰穎,我自認應該是沒辦法不靠任何中斷點就寫出 Bug Free 的程式碼,可是我覺得理解這個題目讓我對於動態規劃的認識多了很多,畢竟是經典題目,多看無益!

975. Odd Even Jump