精華區beta Marginalman 關於我們 聯絡資訊
540. Single Element in a Sorted Array 給你一個已排序整數陣列,裡面的所有數字都有恰好兩個,只有一個數字只有一個, 找出這個數字是什麼,限制時間複雜度:O(logn)且空間複雜度:O(1)。 Example : Input: nums = [1,1,2,3,3,4,4,8,8] Output: 2 Input: nums = [3,3,7,7,10,11,11] Output: 10 思路: 1.看到題目說"陣列已排序"和"時間複雜度O(logn)"就可以確定這題要用二元搜尋來 做了,問題是我們要怎麼樣才能每次查找都捨棄掉一半不必去查的資料。 2.首先做個邊界處理,n == 1 的時候直接返回。 3.把mid作為切點,檢查當前mid這個索引數字的左右兩邊,如果有重複數字就返回兩 個重複數字的索引,否則直接返回nums[mid]。 4.要判斷要往左邊找還是右邊找的條件是:判斷某一半邊的元素數量是否是偶數 舉例來說,若index=[3,4] 1 1 2 3 3 4 4 因為所有數字恰好兩個且只有一個數字只有一個,所以一定有一邊有奇數個元素 所以去除當前重複元素之後的半邊如果有奇數個元素就往那邊找,另一邊捨棄。 5.最後返回nums[l]即可 JavaCode: --------------------------------- class Solution { public int singleNonDuplicate(int[] nums) { int n = nums.length; if (n < 2) { return nums[0]; } int l = 0, r = n - 1; while (l < r) { int mid = (l + r) / 2; int[] index = getIndex(nums, mid); if (index.length == 1) { return nums[mid]; } else if ((index[0] - l) % 2 == 1) { r = index[0] - 1; } else { l = index[1] + 1; } } return nums[l]; } private int[] getIndex(int[] nums, int i) { int n = nums.length; if (i > 0 && nums[i] == nums[i - 1]) { return new int[]{i - 1, i}; } if (i + 1 < n && nums[i] == nums[i + 1]) { return new int[]{i, i + 1}; } return new int[]{i}; } } --------------------------------- 二元搜尋好難 我寫的時候一直邊界炸掉 插滴 -- https://i.imgur.com/uiFto42.jpg -- ※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 36.231.18.126 (臺灣) ※ 文章網址: https://www.ptt.cc/bbs/Marginalman/M.1676951805.A.8F4.html ※ 編輯: Rushia (36.231.18.126 臺灣), 02/21/2023 11:57:39
DDFox: 大師 02/21 11:58
Che31128: 大師 02/21 11:59
abcd991276: 大師 02/21 12:03
NTHUlagka: 大師 想問一下為什麼長度=1時直接回傳0阿 而不是nums[ 02/21 12:23
NTHUlagka: 0] 02/21 12:23
靠北 貼到我第一次WA的程式碼 修正了 ※ 編輯: Rushia (36.231.18.126 臺灣), 02/21/2023 12:25:11
NTHUlagka: 是說你那個判斷不加應該也沒差 底下的二分搜還是能找 02/21 12:37
NTHUlagka: 到答案 02/21 12:37
NTHUlagka: XD想說原來長度1的測資答案剛好是0阿 02/21 12:38
NTHUlagka: 喔喔說錯沒跑二分直接回傳nums[l]就是 02/21 12:40
idiont: 沒有那個判斷 底下檢查會超出邊界 應該是必要的 02/21 12:50
idiont: 沒事 原來有檢查 那應該沒差 02/21 12:50
NTHUlagka: 不會吧 沒那個判斷就不會進入二分搜尋了 因為l==r 02/21 12:51
NTHUlagka: 可能也不需要檢查雙向 我是只有判斷單向 你另一邊會在 02/21 12:52
NTHUlagka: 之後被檢查到 02/21 12:52
Rushia: 對不起 我二元搜尋超爛 02/21 13:17
NTHUlagka: 沒 樓主大師 02/21 13:42
dustsstar79: 大師 02/21 14:03
Mustafar: 何必二分搜?對每個元素,檢查是否與前後相等 02/21 17:25
NTHUlagka: 樓上因為題目要求 02/21 19:28
idiont: 就算題目沒要求 有個執行速度更快的做法也沒不好吧 02/21 20:05
Mustafar: 好好笑我 O(N) 的解 Beats 97.22% 02/22 00:54
Mustafar: 原因也不難猜,大概就因為計算機結構提到的 cache miss 02/22 00:55
Mustafar: 順向的掃過去 cache 都可以命中,二分搜跳來跳去實務上 02/22 00:56
Mustafar: 一定比較快 02/22 00:57
idiont: https://i.imgur.com/4FfwXNl.jpg 還好我的二分搜還是快了 02/22 01:30
idiont: 一點 O(N)會過也只是題目的N不夠大吧 02/22 01:30
Mustafar: N <= 1e6 時 O(N) 本來就夠快啊,除非 1e9 甚至 1e18 02/22 14:27
Mustafar: 才會一定要 O(log N) 甚至 O(1) 02/22 14:28
NTHUlagka: M大的想法蠻有趣的 如果leetcode執行速度真的與cache 02/22 17:42
NTHUlagka: miss有關, 那這樣之後遇到的題目如果限制是10^8, 不知 02/22 17:42
NTHUlagka: 道是否能用O(n)的解法解 感覺是值得嘗試 02/22 17:42
NTHUlagka: 不知道能不能將cache miss量化, 不然這樣很難估實際的 02/22 17:46
NTHUlagka: 複雜度 02/22 17:46
Mustafar: 不過我自己是覺得 LeetCode 的時間本來就很不準 02/24 01:18
Mustafar: 之前現場比賽 N=1e4 我們也是想很久亂丟 O(N^2) 結果 AC 02/24 01:19