[{"data":1,"prerenderedAt":6026},["ShallowReactive",2],{"blog-/blog/leetcode-contest/leetcode-weekly-591":3,"related-/blog/leetcode-contest/leetcode-weekly-591":1903},{"id":4,"title":5,"author":6,"body":7,"category":1887,"date":1888,"description":1889,"extension":1890,"image":33,"language":1891,"meta":1892,"navigation":180,"path":1893,"seo":1894,"stem":1895,"tags":1896,"updatedAt":1901,"__hash__":1902},"blog/blog/Leetcode Contest/leetcode-weekly-591.md","LeetCode Weekly Contest 591 解錄","Ting Zhang",{"type":8,"value":9,"toc":1885},"minimark",[10,21,27,329,334,499,507,520,525,541,992,1000,1003,1024,1033,1038,1183,1187,1494,1502,1505,1525,1539,1543,1705,1709,1881],[11,12,13,14],"p",{},"Q1\n",[15,16,20],"a",{"href":17,"rel":18},"https://leetcode.com/problems/cyclically-shift-rows-and-columns/",[19],"nofollow","Cyclically Shift Rows and Columns",[22,23,24],"blockquote",{},[11,25,26],{},"原始思路：直接把題義內容刻出來\n依照 rowShift / colShift 去對 grid 做 inplace 替換",[28,29,34],"pre",{"className":30,"code":31,"language":32,"meta":33,"style":33},"language-python shiki shiki-themes github-light github-dark","# Space: O(n)\n# Time: O(n^3)\nclass Solution:\n    def cyclicShift(self, n: int, grid: list[list[int]], rowShift: list[int], colShift: list[int]) -> list[list[int]]:\n        for i in range(n):\n            # grid[i] left shift rowShift[i] times\n            for _ in range(rowShift[i]):\n                grid[i] = grid[i][1:] + grid[i][:1]\n\n        # print(grid)\n        for j in range(n):\n            # grid[i][j] upward shift rowShift[i] times\n            for _ in range(colShift[j]):\n                tmp = grid[0][j]\n                for i in range(n):\n                    if i \u003C n - 1:\n                        grid[i][j] = grid[i + 1][j]\n                    else:\n                        grid[i][j] = tmp\n\n        # print(grid)\n        return grid\n","python","",[35,36,37,46,52,67,106,124,130,146,175,182,188,202,208,222,239,253,275,292,300,310,315,320],"code",{"__ignoreMap":33},[38,39,42],"span",{"class":40,"line":41},"line",1,[38,43,45],{"class":44},"sJ8bj","# Space: O(n)\n",[38,47,49],{"class":40,"line":48},2,[38,50,51],{"class":44},"# Time: O(n^3)\n",[38,53,55,59,63],{"class":40,"line":54},3,[38,56,58],{"class":57},"szBVR","class",[38,60,62],{"class":61},"sScJk"," Solution",[38,64,66],{"class":65},"sVt8B",":\n",[38,68,70,73,76,79,83,86,88,91,93,96,98,101,103],{"class":40,"line":69},4,[38,71,72],{"class":57},"    def",[38,74,75],{"class":61}," cyclicShift",[38,77,78],{"class":65},"(self, n: ",[38,80,82],{"class":81},"sj4cs","int",[38,84,85],{"class":65},", grid: list[list[",[38,87,82],{"class":81},[38,89,90],{"class":65},"]], rowShift: list[",[38,92,82],{"class":81},[38,94,95],{"class":65},"], colShift: list[",[38,97,82],{"class":81},[38,99,100],{"class":65},"]) -> list[list[",[38,102,82],{"class":81},[38,104,105],{"class":65},"]]:\n",[38,107,109,112,115,118,121],{"class":40,"line":108},5,[38,110,111],{"class":57},"        for",[38,113,114],{"class":65}," i ",[38,116,117],{"class":57},"in",[38,119,120],{"class":81}," range",[38,122,123],{"class":65},"(n):\n",[38,125,127],{"class":40,"line":126},6,[38,128,129],{"class":44},"            # grid[i] left shift rowShift[i] times\n",[38,131,133,136,139,141,143],{"class":40,"line":132},7,[38,134,135],{"class":57},"            for",[38,137,138],{"class":65}," _ ",[38,140,117],{"class":57},[38,142,120],{"class":81},[38,144,145],{"class":65},"(rowShift[i]):\n",[38,147,149,152,155,158,161,164,167,170,172],{"class":40,"line":148},8,[38,150,151],{"class":65},"                grid[i] ",[38,153,154],{"class":57},"=",[38,156,157],{"class":65}," grid[i][",[38,159,160],{"class":81},"1",[38,162,163],{"class":65},":] ",[38,165,166],{"class":57},"+",[38,168,169],{"class":65}," grid[i][:",[38,171,160],{"class":81},[38,173,174],{"class":65},"]\n",[38,176,178],{"class":40,"line":177},9,[38,179,181],{"emptyLinePlaceholder":180},true,"\n",[38,183,185],{"class":40,"line":184},10,[38,186,187],{"class":44},"        # print(grid)\n",[38,189,191,193,196,198,200],{"class":40,"line":190},11,[38,192,111],{"class":57},[38,194,195],{"class":65}," j ",[38,197,117],{"class":57},[38,199,120],{"class":81},[38,201,123],{"class":65},[38,203,205],{"class":40,"line":204},12,[38,206,207],{"class":44},"            # grid[i][j] upward shift rowShift[i] times\n",[38,209,211,213,215,217,219],{"class":40,"line":210},13,[38,212,135],{"class":57},[38,214,138],{"class":65},[38,216,117],{"class":57},[38,218,120],{"class":81},[38,220,221],{"class":65},"(colShift[j]):\n",[38,223,225,228,230,233,236],{"class":40,"line":224},14,[38,226,227],{"class":65},"                tmp ",[38,229,154],{"class":57},[38,231,232],{"class":65}," grid[",[38,234,235],{"class":81},"0",[38,237,238],{"class":65},"][j]\n",[38,240,242,245,247,249,251],{"class":40,"line":241},15,[38,243,244],{"class":57},"                for",[38,246,114],{"class":65},[38,248,117],{"class":57},[38,250,120],{"class":81},[38,252,123],{"class":65},[38,254,256,259,261,264,267,270,273],{"class":40,"line":255},16,[38,257,258],{"class":57},"                    if",[38,260,114],{"class":65},[38,262,263],{"class":57},"\u003C",[38,265,266],{"class":65}," n ",[38,268,269],{"class":57},"-",[38,271,272],{"class":81}," 1",[38,274,66],{"class":65},[38,276,278,281,283,286,288,290],{"class":40,"line":277},17,[38,279,280],{"class":65},"                        grid[i][j] ",[38,282,154],{"class":57},[38,284,285],{"class":65}," grid[i ",[38,287,166],{"class":57},[38,289,272],{"class":81},[38,291,238],{"class":65},[38,293,295,298],{"class":40,"line":294},18,[38,296,297],{"class":57},"                    else",[38,299,66],{"class":65},[38,301,303,305,307],{"class":40,"line":302},19,[38,304,280],{"class":65},[38,306,154],{"class":57},[38,308,309],{"class":65}," tmp\n",[38,311,313],{"class":40,"line":312},20,[38,314,181],{"emptyLinePlaceholder":180},[38,316,318],{"class":40,"line":317},21,[38,319,187],{"class":44},[38,321,323,326],{"class":40,"line":322},22,[38,324,325],{"class":57},"        return",[38,327,328],{"class":65}," grid\n",[22,330,331],{},[11,332,333],{},"最佳解：用空間複雜度換時間複雜度，建立 result grid\n透過 mod 來取餘數，這樣就可以直接知道當前位置 (i,j) at result 的來源位置  (i,j) at grid",[28,335,337],{"className":30,"code":336,"language":32,"meta":33,"style":33},"# Space: O(n^2)\n# Time: O(n^2)\nclass Solution:\n    def shiftGrid(self, n: int, grid: list[list[int]], rowShift: list[int], colShift: list[int]) -> list[list[int]]:\n        result = [[0] * n for _ in range(n)]\n        for i in range(n):\n            for j in range(n):\n                si = (i + colShift[j]) % n\n                sj = (j + rowShift[si]) % n\n                result[i][j] = grid[si][sj]\n        return result\n",[35,338,339,344,349,357,386,418,430,442,463,482,492],{"__ignoreMap":33},[38,340,341],{"class":40,"line":41},[38,342,343],{"class":44},"# Space: O(n^2)\n",[38,345,346],{"class":40,"line":48},[38,347,348],{"class":44},"# Time: O(n^2)\n",[38,350,351,353,355],{"class":40,"line":54},[38,352,58],{"class":57},[38,354,62],{"class":61},[38,356,66],{"class":65},[38,358,359,361,364,366,368,370,372,374,376,378,380,382,384],{"class":40,"line":69},[38,360,72],{"class":57},[38,362,363],{"class":61}," shiftGrid",[38,365,78],{"class":65},[38,367,82],{"class":81},[38,369,85],{"class":65},[38,371,82],{"class":81},[38,373,90],{"class":65},[38,375,82],{"class":81},[38,377,95],{"class":65},[38,379,82],{"class":81},[38,381,100],{"class":65},[38,383,82],{"class":81},[38,385,105],{"class":65},[38,387,388,391,393,396,398,401,404,406,409,411,413,415],{"class":40,"line":108},[38,389,390],{"class":65},"        result ",[38,392,154],{"class":57},[38,394,395],{"class":65}," [[",[38,397,235],{"class":81},[38,399,400],{"class":65},"] ",[38,402,403],{"class":57},"*",[38,405,266],{"class":65},[38,407,408],{"class":57},"for",[38,410,138],{"class":65},[38,412,117],{"class":57},[38,414,120],{"class":81},[38,416,417],{"class":65},"(n)]\n",[38,419,420,422,424,426,428],{"class":40,"line":126},[38,421,111],{"class":57},[38,423,114],{"class":65},[38,425,117],{"class":57},[38,427,120],{"class":81},[38,429,123],{"class":65},[38,431,432,434,436,438,440],{"class":40,"line":132},[38,433,135],{"class":57},[38,435,195],{"class":65},[38,437,117],{"class":57},[38,439,120],{"class":81},[38,441,123],{"class":65},[38,443,444,447,449,452,454,457,460],{"class":40,"line":148},[38,445,446],{"class":65},"                si ",[38,448,154],{"class":57},[38,450,451],{"class":65}," (i ",[38,453,166],{"class":57},[38,455,456],{"class":65}," colShift[j]) ",[38,458,459],{"class":57},"%",[38,461,462],{"class":65}," n\n",[38,464,465,468,470,473,475,478,480],{"class":40,"line":177},[38,466,467],{"class":65},"                sj ",[38,469,154],{"class":57},[38,471,472],{"class":65}," (j ",[38,474,166],{"class":57},[38,476,477],{"class":65}," rowShift[si]) ",[38,479,459],{"class":57},[38,481,462],{"class":65},[38,483,484,487,489],{"class":40,"line":184},[38,485,486],{"class":65},"                result[i][j] ",[38,488,154],{"class":57},[38,490,491],{"class":65}," grid[si][sj]\n",[38,493,494,496],{"class":40,"line":190},[38,495,325],{"class":57},[38,497,498],{"class":65}," result\n",[11,500,501,502],{},"Q2\n",[15,503,506],{"href":504,"rel":505},"https://leetcode.com/problems/minimum-operations-to-make-every-element-palindromic/",[19],"Minimum Operations to Make Every Element Palindromic",[508,509,510,514,517],"ul",{},[511,512,513],"li",{},"目標：nums 內每個元素都變成正的回文數（如 8、11、121、1221）",[511,515,516],{},"每次操作：選一個元素，只能+2 或 -2",[511,518,519],{},"求最少操作次數",[22,521,522],{},[11,523,524],{},"原始思路：思考回文數字應該要怎麼判斷，但沒有想到僅有窮舉這招",[22,526,527,530],{},[11,528,529],{},"最佳解：",[508,531,532,535,538],{},[511,533,534],{},"先找出 constraint 內所有回文數字，依照奇偶分組 (因為操作只能 +-2, 所以奇偶不會改變)",[511,536,537],{},"透過 Binary Search 找最近 id 對應的回文數字",[511,539,540],{},"求該 num 所需步數",[28,542,544],{"className":30,"code":543,"language":32,"meta":33,"style":33},"from bisect import bisect_left\n\nMAX_VALUE = 10 ** 9\npalindromes_by_parity = [[], []]\n\nfor prefix_num in range(1, 100_000):\n    prefix = str(prefix_num)\n    odd_length = prefix[:-1] + prefix[::-1]\n    even_length = prefix + prefix[::-1]\n\n    odd_palindrome = int(odd_length)\n    even_palindrome = int(even_length)\n\n    if odd_palindrome \u003C MAX_VALUE:\n        palindromes_by_parity[odd_palindrome & 1].append(odd_palindrome)\n    if even_palindrome \u003C MAX_VALUE:\n        palindromes_by_parity[even_palindrome & 1].append(even_palindrome)\n\npalindromes_by_parity[0].sort()\npalindromes_by_parity[1].sort()\n\n\nclass Solution:\n    def minOperations(self, nums: list[int]) -> int:\n        total_ops = 0\n        for num in nums:\n            candidates = palindromes_by_parity[num & 1]\n            idx = bisect_left(candidates, num)\n            if idx >= len(candidates):\n                idx = len(candidates) - 1\n            closest_dist = min(\n                abs(num - candidates[idx]),\n                abs(num - candidates[idx - 1]),\n            )\n            total_ops += closest_dist // 2\n        return total_ops\n",[35,545,546,560,564,581,591,595,620,633,660,680,684,697,709,713,728,741,754,766,770,780,788,792,796,805,825,836,849,866,877,895,913,927,941,960,966,984],{"__ignoreMap":33},[38,547,548,551,554,557],{"class":40,"line":41},[38,549,550],{"class":57},"from",[38,552,553],{"class":65}," bisect ",[38,555,556],{"class":57},"import",[38,558,559],{"class":65}," bisect_left\n",[38,561,562],{"class":40,"line":48},[38,563,181],{"emptyLinePlaceholder":180},[38,565,566,569,572,575,578],{"class":40,"line":54},[38,567,568],{"class":81},"MAX_VALUE",[38,570,571],{"class":57}," =",[38,573,574],{"class":81}," 10",[38,576,577],{"class":57}," **",[38,579,580],{"class":81}," 9\n",[38,582,583,586,588],{"class":40,"line":69},[38,584,585],{"class":65},"palindromes_by_parity ",[38,587,154],{"class":57},[38,589,590],{"class":65}," [[], []]\n",[38,592,593],{"class":40,"line":108},[38,594,181],{"emptyLinePlaceholder":180},[38,596,597,599,602,604,606,609,611,614,617],{"class":40,"line":126},[38,598,408],{"class":57},[38,600,601],{"class":65}," prefix_num ",[38,603,117],{"class":57},[38,605,120],{"class":81},[38,607,608],{"class":65},"(",[38,610,160],{"class":81},[38,612,613],{"class":65},", ",[38,615,616],{"class":81},"100_000",[38,618,619],{"class":65},"):\n",[38,621,622,625,627,630],{"class":40,"line":132},[38,623,624],{"class":65},"    prefix ",[38,626,154],{"class":57},[38,628,629],{"class":81}," str",[38,631,632],{"class":65},"(prefix_num)\n",[38,634,635,638,640,643,645,647,649,651,654,656,658],{"class":40,"line":148},[38,636,637],{"class":65},"    odd_length ",[38,639,154],{"class":57},[38,641,642],{"class":65}," prefix[:",[38,644,269],{"class":57},[38,646,160],{"class":81},[38,648,400],{"class":65},[38,650,166],{"class":57},[38,652,653],{"class":65}," prefix[::",[38,655,269],{"class":57},[38,657,160],{"class":81},[38,659,174],{"class":65},[38,661,662,665,667,670,672,674,676,678],{"class":40,"line":177},[38,663,664],{"class":65},"    even_length ",[38,666,154],{"class":57},[38,668,669],{"class":65}," prefix ",[38,671,166],{"class":57},[38,673,653],{"class":65},[38,675,269],{"class":57},[38,677,160],{"class":81},[38,679,174],{"class":65},[38,681,682],{"class":40,"line":184},[38,683,181],{"emptyLinePlaceholder":180},[38,685,686,689,691,694],{"class":40,"line":190},[38,687,688],{"class":65},"    odd_palindrome ",[38,690,154],{"class":57},[38,692,693],{"class":81}," int",[38,695,696],{"class":65},"(odd_length)\n",[38,698,699,702,704,706],{"class":40,"line":204},[38,700,701],{"class":65},"    even_palindrome ",[38,703,154],{"class":57},[38,705,693],{"class":81},[38,707,708],{"class":65},"(even_length)\n",[38,710,711],{"class":40,"line":210},[38,712,181],{"emptyLinePlaceholder":180},[38,714,715,718,721,723,726],{"class":40,"line":224},[38,716,717],{"class":57},"    if",[38,719,720],{"class":65}," odd_palindrome ",[38,722,263],{"class":57},[38,724,725],{"class":81}," MAX_VALUE",[38,727,66],{"class":65},[38,729,730,733,736,738],{"class":40,"line":241},[38,731,732],{"class":65},"        palindromes_by_parity[odd_palindrome ",[38,734,735],{"class":57},"&",[38,737,272],{"class":81},[38,739,740],{"class":65},"].append(odd_palindrome)\n",[38,742,743,745,748,750,752],{"class":40,"line":255},[38,744,717],{"class":57},[38,746,747],{"class":65}," even_palindrome ",[38,749,263],{"class":57},[38,751,725],{"class":81},[38,753,66],{"class":65},[38,755,756,759,761,763],{"class":40,"line":277},[38,757,758],{"class":65},"        palindromes_by_parity[even_palindrome ",[38,760,735],{"class":57},[38,762,272],{"class":81},[38,764,765],{"class":65},"].append(even_palindrome)\n",[38,767,768],{"class":40,"line":294},[38,769,181],{"emptyLinePlaceholder":180},[38,771,772,775,777],{"class":40,"line":302},[38,773,774],{"class":65},"palindromes_by_parity[",[38,776,235],{"class":81},[38,778,779],{"class":65},"].sort()\n",[38,781,782,784,786],{"class":40,"line":312},[38,783,774],{"class":65},[38,785,160],{"class":81},[38,787,779],{"class":65},[38,789,790],{"class":40,"line":317},[38,791,181],{"emptyLinePlaceholder":180},[38,793,794],{"class":40,"line":322},[38,795,181],{"emptyLinePlaceholder":180},[38,797,799,801,803],{"class":40,"line":798},23,[38,800,58],{"class":57},[38,802,62],{"class":61},[38,804,66],{"class":65},[38,806,808,810,813,816,818,821,823],{"class":40,"line":807},24,[38,809,72],{"class":57},[38,811,812],{"class":61}," minOperations",[38,814,815],{"class":65},"(self, nums: list[",[38,817,82],{"class":81},[38,819,820],{"class":65},"]) -> ",[38,822,82],{"class":81},[38,824,66],{"class":65},[38,826,828,831,833],{"class":40,"line":827},25,[38,829,830],{"class":65},"        total_ops ",[38,832,154],{"class":57},[38,834,835],{"class":81}," 0\n",[38,837,839,841,844,846],{"class":40,"line":838},26,[38,840,111],{"class":57},[38,842,843],{"class":65}," num ",[38,845,117],{"class":57},[38,847,848],{"class":65}," nums:\n",[38,850,852,855,857,860,862,864],{"class":40,"line":851},27,[38,853,854],{"class":65},"            candidates ",[38,856,154],{"class":57},[38,858,859],{"class":65}," palindromes_by_parity[num ",[38,861,735],{"class":57},[38,863,272],{"class":81},[38,865,174],{"class":65},[38,867,869,872,874],{"class":40,"line":868},28,[38,870,871],{"class":65},"            idx ",[38,873,154],{"class":57},[38,875,876],{"class":65}," bisect_left(candidates, num)\n",[38,878,880,883,886,889,892],{"class":40,"line":879},29,[38,881,882],{"class":57},"            if",[38,884,885],{"class":65}," idx ",[38,887,888],{"class":57},">=",[38,890,891],{"class":81}," len",[38,893,894],{"class":65},"(candidates):\n",[38,896,898,901,903,905,908,910],{"class":40,"line":897},30,[38,899,900],{"class":65},"                idx ",[38,902,154],{"class":57},[38,904,891],{"class":81},[38,906,907],{"class":65},"(candidates) ",[38,909,269],{"class":57},[38,911,912],{"class":81}," 1\n",[38,914,916,919,921,924],{"class":40,"line":915},31,[38,917,918],{"class":65},"            closest_dist ",[38,920,154],{"class":57},[38,922,923],{"class":81}," min",[38,925,926],{"class":65},"(\n",[38,928,930,933,936,938],{"class":40,"line":929},32,[38,931,932],{"class":81},"                abs",[38,934,935],{"class":65},"(num ",[38,937,269],{"class":57},[38,939,940],{"class":65}," candidates[idx]),\n",[38,942,944,946,948,950,953,955,957],{"class":40,"line":943},33,[38,945,932],{"class":81},[38,947,935],{"class":65},[38,949,269],{"class":57},[38,951,952],{"class":65}," candidates[idx ",[38,954,269],{"class":57},[38,956,272],{"class":81},[38,958,959],{"class":65},"]),\n",[38,961,963],{"class":40,"line":962},34,[38,964,965],{"class":65},"            )\n",[38,967,969,972,975,978,981],{"class":40,"line":968},35,[38,970,971],{"class":65},"            total_ops ",[38,973,974],{"class":57},"+=",[38,976,977],{"class":65}," closest_dist ",[38,979,980],{"class":57},"//",[38,982,983],{"class":81}," 2\n",[38,985,987,989],{"class":40,"line":986},36,[38,988,325],{"class":57},[38,990,991],{"class":65}," total_ops\n",[11,993,994,995],{},"Q3\n",[15,996,999],{"href":997,"rel":998},"https://leetcode.com/problems/count-shadow-pairs-i/",[19],"Count Shadow Pairs I",[11,1001,1002],{},"題目敘述我覺得蠻容易把自己繞昏的，總之我們在找一個 index pair，符合以下條件",[1004,1005,1006,1011,1017],"ol",{},[511,1007,1008],{},[35,1009,1010],{},"i \u003C j",[511,1012,1013,1016],{},[35,1014,1015],{},"nums[i] \u003C nums[j]","（左邊比右邊小）",[511,1018,1019,1020,1023],{},"i 和 j 之間沒有任何元素比 ",[35,1021,1022],{},"nums[i]"," 更小",[11,1025,1026,1027,1029,1030,1032],{},"我們可以做一次 for 迴圈並維護一個 Stack，檢查 ",[35,1028,1022],{}," 右邊是否有比 ",[35,1031,1022],{}," 更小的值\n也就是説一個 x 進來以後，我們用 for 迴圈檢查 top of stack 是否 > x, 如果是的話我們就把 top of stack pop 掉\n完成以後我們可以說 stack 內 \"去除 = x 的\" 所有元素都是一個合法的 i, 當前的 x index 為合法的 j，這時候的 i, j 都是合法的 pair",[22,1034,1035],{},[11,1036,1037],{},"原本思路：沒想到什麼特別的，依照題目內容刻了一個 time n^2 會 TLE 的解",[28,1039,1041],{"className":30,"code":1040,"language":32,"meta":33,"style":33},"# TLE\nclass Solution:\n    def shadowPairs(self, nums: list[int]) -> int:\n        n = len(nums)\n        res = 0\n        for i in range(n):\n            for j in range(n):\n                if j \u003C= i:\n                    continue\n                if nums[j] \u003C nums[i]:\n                    break\n                if nums[j] \u003C= nums[i]:\n                    continue\n                res += 1\n        return res\n\n",[35,1042,1043,1048,1056,1073,1085,1094,1106,1118,1131,1136,1148,1153,1163,1167,1176],{"__ignoreMap":33},[38,1044,1045],{"class":40,"line":41},[38,1046,1047],{"class":44},"# TLE\n",[38,1049,1050,1052,1054],{"class":40,"line":48},[38,1051,58],{"class":57},[38,1053,62],{"class":61},[38,1055,66],{"class":65},[38,1057,1058,1060,1063,1065,1067,1069,1071],{"class":40,"line":54},[38,1059,72],{"class":57},[38,1061,1062],{"class":61}," shadowPairs",[38,1064,815],{"class":65},[38,1066,82],{"class":81},[38,1068,820],{"class":65},[38,1070,82],{"class":81},[38,1072,66],{"class":65},[38,1074,1075,1078,1080,1082],{"class":40,"line":69},[38,1076,1077],{"class":65},"        n ",[38,1079,154],{"class":57},[38,1081,891],{"class":81},[38,1083,1084],{"class":65},"(nums)\n",[38,1086,1087,1090,1092],{"class":40,"line":108},[38,1088,1089],{"class":65},"        res ",[38,1091,154],{"class":57},[38,1093,835],{"class":81},[38,1095,1096,1098,1100,1102,1104],{"class":40,"line":126},[38,1097,111],{"class":57},[38,1099,114],{"class":65},[38,1101,117],{"class":57},[38,1103,120],{"class":81},[38,1105,123],{"class":65},[38,1107,1108,1110,1112,1114,1116],{"class":40,"line":132},[38,1109,135],{"class":57},[38,1111,195],{"class":65},[38,1113,117],{"class":57},[38,1115,120],{"class":81},[38,1117,123],{"class":65},[38,1119,1120,1123,1125,1128],{"class":40,"line":148},[38,1121,1122],{"class":57},"                if",[38,1124,195],{"class":65},[38,1126,1127],{"class":57},"\u003C=",[38,1129,1130],{"class":65}," i:\n",[38,1132,1133],{"class":40,"line":177},[38,1134,1135],{"class":57},"                    continue\n",[38,1137,1138,1140,1143,1145],{"class":40,"line":184},[38,1139,1122],{"class":57},[38,1141,1142],{"class":65}," nums[j] ",[38,1144,263],{"class":57},[38,1146,1147],{"class":65}," nums[i]:\n",[38,1149,1150],{"class":40,"line":190},[38,1151,1152],{"class":57},"                    break\n",[38,1154,1155,1157,1159,1161],{"class":40,"line":204},[38,1156,1122],{"class":57},[38,1158,1142],{"class":65},[38,1160,1127],{"class":57},[38,1162,1147],{"class":65},[38,1164,1165],{"class":40,"line":210},[38,1166,1135],{"class":57},[38,1168,1169,1172,1174],{"class":40,"line":224},[38,1170,1171],{"class":65},"                res ",[38,1173,974],{"class":57},[38,1175,912],{"class":81},[38,1177,1178,1180],{"class":40,"line":241},[38,1179,325],{"class":57},[38,1181,1182],{"class":65}," res\n",[22,1184,1185],{},[11,1186,529],{},[28,1188,1190],{"className":30,"code":1189,"language":32,"meta":33,"style":33},"class Solution:\n    def countShadowPairs(self, nums: list[int]) -> int:\n        stack = []          # (value, count), non-decreasing\n        total_in_stack = 0  # sum of all counts in the stack\n        ans = 0\n\n        for x in nums:\n            # Pop elements > x — they can never pair again\n            while stack and stack[-1][0] > x:\n                total_in_stack -= stack.pop()[1]\n\n            # Count elements strictly \u003C x\n            if stack and stack[-1][0] == x:\n                ans += total_in_stack - stack[-1][1]\n            else:\n                ans += total_in_stack\n\n            # Push x (merge if top has same value)\n            if stack and stack[-1][0] == x:\n                stack[-1] = (x, stack[-1][1] + 1)\n            else:\n                stack.append((x, 1))\n            total_in_stack += 1\n\n        return ans\n",[35,1191,1192,1200,1217,1230,1243,1252,1256,1267,1272,1303,1318,1322,1327,1352,1376,1383,1392,1396,1401,1425,1458,1464,1474,1483,1487],{"__ignoreMap":33},[38,1193,1194,1196,1198],{"class":40,"line":41},[38,1195,58],{"class":57},[38,1197,62],{"class":61},[38,1199,66],{"class":65},[38,1201,1202,1204,1207,1209,1211,1213,1215],{"class":40,"line":48},[38,1203,72],{"class":57},[38,1205,1206],{"class":61}," countShadowPairs",[38,1208,815],{"class":65},[38,1210,82],{"class":81},[38,1212,820],{"class":65},[38,1214,82],{"class":81},[38,1216,66],{"class":65},[38,1218,1219,1222,1224,1227],{"class":40,"line":54},[38,1220,1221],{"class":65},"        stack ",[38,1223,154],{"class":57},[38,1225,1226],{"class":65}," []          ",[38,1228,1229],{"class":44},"# (value, count), non-decreasing\n",[38,1231,1232,1235,1237,1240],{"class":40,"line":69},[38,1233,1234],{"class":65},"        total_in_stack ",[38,1236,154],{"class":57},[38,1238,1239],{"class":81}," 0",[38,1241,1242],{"class":44},"  # sum of all counts in the stack\n",[38,1244,1245,1248,1250],{"class":40,"line":108},[38,1246,1247],{"class":65},"        ans ",[38,1249,154],{"class":57},[38,1251,835],{"class":81},[38,1253,1254],{"class":40,"line":126},[38,1255,181],{"emptyLinePlaceholder":180},[38,1257,1258,1260,1263,1265],{"class":40,"line":132},[38,1259,111],{"class":57},[38,1261,1262],{"class":65}," x ",[38,1264,117],{"class":57},[38,1266,848],{"class":65},[38,1268,1269],{"class":40,"line":148},[38,1270,1271],{"class":44},"            # Pop elements > x — they can never pair again\n",[38,1273,1274,1277,1280,1283,1286,1288,1290,1293,1295,1297,1300],{"class":40,"line":177},[38,1275,1276],{"class":57},"            while",[38,1278,1279],{"class":65}," stack ",[38,1281,1282],{"class":57},"and",[38,1284,1285],{"class":65}," stack[",[38,1287,269],{"class":57},[38,1289,160],{"class":81},[38,1291,1292],{"class":65},"][",[38,1294,235],{"class":81},[38,1296,400],{"class":65},[38,1298,1299],{"class":57},">",[38,1301,1302],{"class":65}," x:\n",[38,1304,1305,1308,1311,1314,1316],{"class":40,"line":184},[38,1306,1307],{"class":65},"                total_in_stack ",[38,1309,1310],{"class":57},"-=",[38,1312,1313],{"class":65}," stack.pop()[",[38,1315,160],{"class":81},[38,1317,174],{"class":65},[38,1319,1320],{"class":40,"line":190},[38,1321,181],{"emptyLinePlaceholder":180},[38,1323,1324],{"class":40,"line":204},[38,1325,1326],{"class":44},"            # Count elements strictly \u003C x\n",[38,1328,1329,1331,1333,1335,1337,1339,1341,1343,1345,1347,1350],{"class":40,"line":210},[38,1330,882],{"class":57},[38,1332,1279],{"class":65},[38,1334,1282],{"class":57},[38,1336,1285],{"class":65},[38,1338,269],{"class":57},[38,1340,160],{"class":81},[38,1342,1292],{"class":65},[38,1344,235],{"class":81},[38,1346,400],{"class":65},[38,1348,1349],{"class":57},"==",[38,1351,1302],{"class":65},[38,1353,1354,1357,1359,1362,1364,1366,1368,1370,1372,1374],{"class":40,"line":224},[38,1355,1356],{"class":65},"                ans ",[38,1358,974],{"class":57},[38,1360,1361],{"class":65}," total_in_stack ",[38,1363,269],{"class":57},[38,1365,1285],{"class":65},[38,1367,269],{"class":57},[38,1369,160],{"class":81},[38,1371,1292],{"class":65},[38,1373,160],{"class":81},[38,1375,174],{"class":65},[38,1377,1378,1381],{"class":40,"line":241},[38,1379,1380],{"class":57},"            else",[38,1382,66],{"class":65},[38,1384,1385,1387,1389],{"class":40,"line":255},[38,1386,1356],{"class":65},[38,1388,974],{"class":57},[38,1390,1391],{"class":65}," total_in_stack\n",[38,1393,1394],{"class":40,"line":277},[38,1395,181],{"emptyLinePlaceholder":180},[38,1397,1398],{"class":40,"line":294},[38,1399,1400],{"class":44},"            # Push x (merge if top has same value)\n",[38,1402,1403,1405,1407,1409,1411,1413,1415,1417,1419,1421,1423],{"class":40,"line":302},[38,1404,882],{"class":57},[38,1406,1279],{"class":65},[38,1408,1282],{"class":57},[38,1410,1285],{"class":65},[38,1412,269],{"class":57},[38,1414,160],{"class":81},[38,1416,1292],{"class":65},[38,1418,235],{"class":81},[38,1420,400],{"class":65},[38,1422,1349],{"class":57},[38,1424,1302],{"class":65},[38,1426,1427,1430,1432,1434,1436,1438,1441,1443,1445,1447,1449,1451,1453,1455],{"class":40,"line":312},[38,1428,1429],{"class":65},"                stack[",[38,1431,269],{"class":57},[38,1433,160],{"class":81},[38,1435,400],{"class":65},[38,1437,154],{"class":57},[38,1439,1440],{"class":65}," (x, stack[",[38,1442,269],{"class":57},[38,1444,160],{"class":81},[38,1446,1292],{"class":65},[38,1448,160],{"class":81},[38,1450,400],{"class":65},[38,1452,166],{"class":57},[38,1454,272],{"class":81},[38,1456,1457],{"class":65},")\n",[38,1459,1460,1462],{"class":40,"line":317},[38,1461,1380],{"class":57},[38,1463,66],{"class":65},[38,1465,1466,1469,1471],{"class":40,"line":322},[38,1467,1468],{"class":65},"                stack.append((x, ",[38,1470,160],{"class":81},[38,1472,1473],{"class":65},"))\n",[38,1475,1476,1479,1481],{"class":40,"line":798},[38,1477,1478],{"class":65},"            total_in_stack ",[38,1480,974],{"class":57},[38,1482,912],{"class":81},[38,1484,1485],{"class":40,"line":807},[38,1486,181],{"emptyLinePlaceholder":180},[38,1488,1489,1491],{"class":40,"line":827},[38,1490,325],{"class":57},[38,1492,1493],{"class":65}," ans\n",[11,1495,1496,1497],{},"Q4\n",[15,1498,1501],{"href":1499,"rel":1500},"https://leetcode.com/problems/count-shadow-pairs-ii/",[19],"Count Shadow Pairs II",[11,1503,1504],{},"跟上一題幾乎一樣，條件為",[1004,1506,1507,1511,1515],{},[511,1508,1509],{},[35,1510,1010],{},[511,1512,1513],{},[35,1514,1015],{},[511,1516,1517,1518,1521,1522],{},"i 和 j 之間不存在 k，使得 ",[35,1519,1520],{},"nums[i] \u003C nums[k] \u003C nums[j]","，這邊上一題是不存在 ",[35,1523,1524],{},"nums[k] \u003C nums[i] \u003C nums[j]",[11,1526,1527,1528,1531,1532,1534,1535,1538],{},"維護的 stack 改成 ",[35,1529,1530],{},"比 nums[j] 小的元素會被 pop 出來","\n每個被 pop 的元素 ",[35,1533,1022],{}," 和 ",[35,1536,1537],{},"nums[j]"," 形成一對 shadow pair",[22,1540,1541],{},[11,1542,1037],{},[28,1544,1546],{"className":30,"code":1545,"language":32,"meta":33,"style":33},"# TLE\nclass Solution:\n    def shadowPairs(self, nums: list[int]) -> int:\n        n = len(nums)\n        res = 0\n        for i in range(n):\n            tmp_min = float('inf')\n            for j in range(n):\n                if j \u003C= i:\n                    continue\n                if nums[j] \u003C= nums[i]:\n                    continue\n                if nums[j] > tmp_min:\n                    continue\n                tmp_min = min(tmp_min, nums[j])\n                res += 1\n        return res\n",[35,1547,1548,1552,1560,1576,1586,1594,1606,1624,1636,1646,1650,1660,1664,1675,1679,1691,1699],{"__ignoreMap":33},[38,1549,1550],{"class":40,"line":41},[38,1551,1047],{"class":44},[38,1553,1554,1556,1558],{"class":40,"line":48},[38,1555,58],{"class":57},[38,1557,62],{"class":61},[38,1559,66],{"class":65},[38,1561,1562,1564,1566,1568,1570,1572,1574],{"class":40,"line":54},[38,1563,72],{"class":57},[38,1565,1062],{"class":61},[38,1567,815],{"class":65},[38,1569,82],{"class":81},[38,1571,820],{"class":65},[38,1573,82],{"class":81},[38,1575,66],{"class":65},[38,1577,1578,1580,1582,1584],{"class":40,"line":69},[38,1579,1077],{"class":65},[38,1581,154],{"class":57},[38,1583,891],{"class":81},[38,1585,1084],{"class":65},[38,1587,1588,1590,1592],{"class":40,"line":108},[38,1589,1089],{"class":65},[38,1591,154],{"class":57},[38,1593,835],{"class":81},[38,1595,1596,1598,1600,1602,1604],{"class":40,"line":126},[38,1597,111],{"class":57},[38,1599,114],{"class":65},[38,1601,117],{"class":57},[38,1603,120],{"class":81},[38,1605,123],{"class":65},[38,1607,1608,1611,1613,1616,1618,1622],{"class":40,"line":132},[38,1609,1610],{"class":65},"            tmp_min ",[38,1612,154],{"class":57},[38,1614,1615],{"class":81}," float",[38,1617,608],{"class":65},[38,1619,1621],{"class":1620},"sZZnC","'inf'",[38,1623,1457],{"class":65},[38,1625,1626,1628,1630,1632,1634],{"class":40,"line":148},[38,1627,135],{"class":57},[38,1629,195],{"class":65},[38,1631,117],{"class":57},[38,1633,120],{"class":81},[38,1635,123],{"class":65},[38,1637,1638,1640,1642,1644],{"class":40,"line":177},[38,1639,1122],{"class":57},[38,1641,195],{"class":65},[38,1643,1127],{"class":57},[38,1645,1130],{"class":65},[38,1647,1648],{"class":40,"line":184},[38,1649,1135],{"class":57},[38,1651,1652,1654,1656,1658],{"class":40,"line":190},[38,1653,1122],{"class":57},[38,1655,1142],{"class":65},[38,1657,1127],{"class":57},[38,1659,1147],{"class":65},[38,1661,1662],{"class":40,"line":204},[38,1663,1135],{"class":57},[38,1665,1666,1668,1670,1672],{"class":40,"line":210},[38,1667,1122],{"class":57},[38,1669,1142],{"class":65},[38,1671,1299],{"class":57},[38,1673,1674],{"class":65}," tmp_min:\n",[38,1676,1677],{"class":40,"line":224},[38,1678,1135],{"class":57},[38,1680,1681,1684,1686,1688],{"class":40,"line":241},[38,1682,1683],{"class":65},"                tmp_min ",[38,1685,154],{"class":57},[38,1687,923],{"class":81},[38,1689,1690],{"class":65},"(tmp_min, nums[j])\n",[38,1692,1693,1695,1697],{"class":40,"line":255},[38,1694,1171],{"class":65},[38,1696,974],{"class":57},[38,1698,912],{"class":81},[38,1700,1701,1703],{"class":40,"line":277},[38,1702,325],{"class":57},[38,1704,1182],{"class":65},[22,1706,1707],{},[11,1708,529],{},[28,1710,1712],{"className":30,"code":1711,"language":32,"meta":33,"style":33},"class Solution:\n    def countShadowPairs(self, nums: list[int]) -> int:\n        stack = []  # (value, count), monotonically decreasing\n        result = 0\n\n        for x in nums:\n            count = 1\n            while stack and stack[-1][0] \u003C x:\n                val, cnt = stack.pop()\n                result += cnt\n            if stack and stack[-1][0] == x:\n                val, cnt = stack.pop()\n                count += cnt\n            stack.append((x, count))\n\n        return result\n",[35,1713,1714,1722,1738,1750,1758,1762,1772,1781,1805,1815,1825,1849,1857,1866,1871,1875],{"__ignoreMap":33},[38,1715,1716,1718,1720],{"class":40,"line":41},[38,1717,58],{"class":57},[38,1719,62],{"class":61},[38,1721,66],{"class":65},[38,1723,1724,1726,1728,1730,1732,1734,1736],{"class":40,"line":48},[38,1725,72],{"class":57},[38,1727,1206],{"class":61},[38,1729,815],{"class":65},[38,1731,82],{"class":81},[38,1733,820],{"class":65},[38,1735,82],{"class":81},[38,1737,66],{"class":65},[38,1739,1740,1742,1744,1747],{"class":40,"line":54},[38,1741,1221],{"class":65},[38,1743,154],{"class":57},[38,1745,1746],{"class":65}," []  ",[38,1748,1749],{"class":44},"# (value, count), monotonically decreasing\n",[38,1751,1752,1754,1756],{"class":40,"line":69},[38,1753,390],{"class":65},[38,1755,154],{"class":57},[38,1757,835],{"class":81},[38,1759,1760],{"class":40,"line":108},[38,1761,181],{"emptyLinePlaceholder":180},[38,1763,1764,1766,1768,1770],{"class":40,"line":126},[38,1765,111],{"class":57},[38,1767,1262],{"class":65},[38,1769,117],{"class":57},[38,1771,848],{"class":65},[38,1773,1774,1777,1779],{"class":40,"line":132},[38,1775,1776],{"class":65},"            count ",[38,1778,154],{"class":57},[38,1780,912],{"class":81},[38,1782,1783,1785,1787,1789,1791,1793,1795,1797,1799,1801,1803],{"class":40,"line":148},[38,1784,1276],{"class":57},[38,1786,1279],{"class":65},[38,1788,1282],{"class":57},[38,1790,1285],{"class":65},[38,1792,269],{"class":57},[38,1794,160],{"class":81},[38,1796,1292],{"class":65},[38,1798,235],{"class":81},[38,1800,400],{"class":65},[38,1802,263],{"class":57},[38,1804,1302],{"class":65},[38,1806,1807,1810,1812],{"class":40,"line":177},[38,1808,1809],{"class":65},"                val, cnt ",[38,1811,154],{"class":57},[38,1813,1814],{"class":65}," stack.pop()\n",[38,1816,1817,1820,1822],{"class":40,"line":184},[38,1818,1819],{"class":65},"                result ",[38,1821,974],{"class":57},[38,1823,1824],{"class":65}," cnt\n",[38,1826,1827,1829,1831,1833,1835,1837,1839,1841,1843,1845,1847],{"class":40,"line":190},[38,1828,882],{"class":57},[38,1830,1279],{"class":65},[38,1832,1282],{"class":57},[38,1834,1285],{"class":65},[38,1836,269],{"class":57},[38,1838,160],{"class":81},[38,1840,1292],{"class":65},[38,1842,235],{"class":81},[38,1844,400],{"class":65},[38,1846,1349],{"class":57},[38,1848,1302],{"class":65},[38,1850,1851,1853,1855],{"class":40,"line":204},[38,1852,1809],{"class":65},[38,1854,154],{"class":57},[38,1856,1814],{"class":65},[38,1858,1859,1862,1864],{"class":40,"line":210},[38,1860,1861],{"class":65},"                count ",[38,1863,974],{"class":57},[38,1865,1824],{"class":65},[38,1867,1868],{"class":40,"line":224},[38,1869,1870],{"class":65},"            stack.append((x, count))\n",[38,1872,1873],{"class":40,"line":241},[38,1874,181],{"emptyLinePlaceholder":180},[38,1876,1877,1879],{"class":40,"line":255},[38,1878,325],{"class":57},[38,1880,498],{"class":65},[1882,1883,1884],"style",{},"html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}",{"title":33,"searchDepth":48,"depth":48,"links":1886},[],"技術","2026-09-19","Weekly Contest 591 過程思路與心得","md","zh-TW",{},"/blog/leetcode-contest/leetcode-weekly-591",{"title":5,"description":1889},"blog/Leetcode Contest/leetcode-weekly-591",[1897,1898,1899,1900],"LeetCode","Contest","Algorithm","Python",null,"WAX25mKJ1n2dKDKj76DIjEpDlybg1uqtWLTLUnlYIlE",[1904,3527,5632],{"id":1905,"title":1906,"author":6,"body":1907,"category":1887,"date":1888,"description":3520,"extension":1890,"image":33,"language":1891,"meta":3521,"navigation":180,"path":3522,"seo":3523,"stem":3524,"tags":3525,"updatedAt":1901,"__hash__":3526},"blog/blog/Leetcode Contest/leetcode-biweekly-191.md","LeetCode Biweekly Contest 191 紀錄",{"type":8,"value":1908,"toc":3518},[1909,1916,1921,2100,2107,2110,2115,2397,2404,2407,2412,2767,2775,2780,2785,2788,2791,2813,3515],[11,1910,13,1911],{},[15,1912,1915],{"href":1913,"rel":1914},"https://leetcode.com/problems/count-values-with-equally-spaced-occurrences-i/",[19],"Count Values With Equally Spaced Occurrences I",[22,1917,1918],{},[11,1919,1920],{},"原本思路：把題目定義的條件刻出來，沒什麼特別的",[28,1922,1924],{"className":30,"code":1923,"language":32,"meta":33,"style":33},"class Solution:\n    def countSpecialIntegers(self, nums: list[int]) -> int:\n        seen = {}\n        res = 0\n        for i, num in enumerate(nums):\n            if num in seen:\n                seen[num].append(i)\n            else:\n                seen[num] = [i]\n\n        # print(seen)\n        for key in seen:\n            if len(seen[key]) == 3 and seen[key][2] - seen[key][1] == seen[key][1] - seen[key][0]:\n                res += 1\n        return res\n",[35,1925,1926,1934,1951,1961,1969,1984,1995,2000,2006,2016,2020,2025,2036,2086,2094],{"__ignoreMap":33},[38,1927,1928,1930,1932],{"class":40,"line":41},[38,1929,58],{"class":57},[38,1931,62],{"class":61},[38,1933,66],{"class":65},[38,1935,1936,1938,1941,1943,1945,1947,1949],{"class":40,"line":48},[38,1937,72],{"class":57},[38,1939,1940],{"class":61}," countSpecialIntegers",[38,1942,815],{"class":65},[38,1944,82],{"class":81},[38,1946,820],{"class":65},[38,1948,82],{"class":81},[38,1950,66],{"class":65},[38,1952,1953,1956,1958],{"class":40,"line":54},[38,1954,1955],{"class":65},"        seen ",[38,1957,154],{"class":57},[38,1959,1960],{"class":65}," {}\n",[38,1962,1963,1965,1967],{"class":40,"line":69},[38,1964,1089],{"class":65},[38,1966,154],{"class":57},[38,1968,835],{"class":81},[38,1970,1971,1973,1976,1978,1981],{"class":40,"line":108},[38,1972,111],{"class":57},[38,1974,1975],{"class":65}," i, num ",[38,1977,117],{"class":57},[38,1979,1980],{"class":81}," enumerate",[38,1982,1983],{"class":65},"(nums):\n",[38,1985,1986,1988,1990,1992],{"class":40,"line":126},[38,1987,882],{"class":57},[38,1989,843],{"class":65},[38,1991,117],{"class":57},[38,1993,1994],{"class":65}," seen:\n",[38,1996,1997],{"class":40,"line":132},[38,1998,1999],{"class":65},"                seen[num].append(i)\n",[38,2001,2002,2004],{"class":40,"line":148},[38,2003,1380],{"class":57},[38,2005,66],{"class":65},[38,2007,2008,2011,2013],{"class":40,"line":177},[38,2009,2010],{"class":65},"                seen[num] ",[38,2012,154],{"class":57},[38,2014,2015],{"class":65}," [i]\n",[38,2017,2018],{"class":40,"line":184},[38,2019,181],{"emptyLinePlaceholder":180},[38,2021,2022],{"class":40,"line":190},[38,2023,2024],{"class":44},"        # print(seen)\n",[38,2026,2027,2029,2032,2034],{"class":40,"line":204},[38,2028,111],{"class":57},[38,2030,2031],{"class":65}," key ",[38,2033,117],{"class":57},[38,2035,1994],{"class":65},[38,2037,2038,2040,2042,2045,2047,2050,2053,2056,2059,2061,2063,2065,2067,2069,2071,2073,2075,2077,2079,2081,2083],{"class":40,"line":210},[38,2039,882],{"class":57},[38,2041,891],{"class":81},[38,2043,2044],{"class":65},"(seen[key]) ",[38,2046,1349],{"class":57},[38,2048,2049],{"class":81}," 3",[38,2051,2052],{"class":57}," and",[38,2054,2055],{"class":65}," seen[key][",[38,2057,2058],{"class":81},"2",[38,2060,400],{"class":65},[38,2062,269],{"class":57},[38,2064,2055],{"class":65},[38,2066,160],{"class":81},[38,2068,400],{"class":65},[38,2070,1349],{"class":57},[38,2072,2055],{"class":65},[38,2074,160],{"class":81},[38,2076,400],{"class":65},[38,2078,269],{"class":57},[38,2080,2055],{"class":65},[38,2082,235],{"class":81},[38,2084,2085],{"class":65},"]:\n",[38,2087,2088,2090,2092],{"class":40,"line":224},[38,2089,1171],{"class":65},[38,2091,974],{"class":57},[38,2093,912],{"class":81},[38,2095,2096,2098],{"class":40,"line":241},[38,2097,325],{"class":57},[38,2099,1182],{"class":65},[11,2101,501,2102],{},[15,2103,2106],{"href":2104,"rel":2105},"https://leetcode.com/problems/count-values-with-equally-spaced-occurrences-ii/",[19],"Count Values With Equally Spaced Occurrences II",[11,2108,2109],{},"上一題的進階版，判定條件從 3 個變成 n 個",[22,2111,2112],{},[11,2113,2114],{},"原始思路：改成透過 for 迴圈處理判定",[28,2116,2118],{"className":30,"code":2117,"language":32,"meta":33,"style":33},"class Solution:\n    def countSpecialIntegers(self, nums: list[int]) -> int:\n        seen = {}\n        res = 0\n        for i, num in enumerate(nums):\n            if num in seen:\n                seen[num].append(i)\n            else:\n                seen[num] = [i]\n\n        # print(seen)\n        for key in seen:\n            if len(seen[key]) \u003C 3:\n                continue\n\n            first = seen[key][0]\n            second = seen[key][1]\n            gap = first - second\n            fail = False\n            # print(seen[key][2:])\n            for num in seen[key][2:]:\n                # print(second, num, gap)\n                if gap != second - num:\n                    fail = True\n                    break\n                else:\n                    second = num\n            if fail:\n                continue\n            else:\n                res += 1\n        return res\n",[35,2119,2120,2128,2144,2152,2160,2172,2182,2186,2192,2200,2204,2208,2218,2232,2237,2241,2254,2267,2282,2292,2297,2312,2317,2335,2345,2349,2356,2366,2373,2377,2383,2391],{"__ignoreMap":33},[38,2121,2122,2124,2126],{"class":40,"line":41},[38,2123,58],{"class":57},[38,2125,62],{"class":61},[38,2127,66],{"class":65},[38,2129,2130,2132,2134,2136,2138,2140,2142],{"class":40,"line":48},[38,2131,72],{"class":57},[38,2133,1940],{"class":61},[38,2135,815],{"class":65},[38,2137,82],{"class":81},[38,2139,820],{"class":65},[38,2141,82],{"class":81},[38,2143,66],{"class":65},[38,2145,2146,2148,2150],{"class":40,"line":54},[38,2147,1955],{"class":65},[38,2149,154],{"class":57},[38,2151,1960],{"class":65},[38,2153,2154,2156,2158],{"class":40,"line":69},[38,2155,1089],{"class":65},[38,2157,154],{"class":57},[38,2159,835],{"class":81},[38,2161,2162,2164,2166,2168,2170],{"class":40,"line":108},[38,2163,111],{"class":57},[38,2165,1975],{"class":65},[38,2167,117],{"class":57},[38,2169,1980],{"class":81},[38,2171,1983],{"class":65},[38,2173,2174,2176,2178,2180],{"class":40,"line":126},[38,2175,882],{"class":57},[38,2177,843],{"class":65},[38,2179,117],{"class":57},[38,2181,1994],{"class":65},[38,2183,2184],{"class":40,"line":132},[38,2185,1999],{"class":65},[38,2187,2188,2190],{"class":40,"line":148},[38,2189,1380],{"class":57},[38,2191,66],{"class":65},[38,2193,2194,2196,2198],{"class":40,"line":177},[38,2195,2010],{"class":65},[38,2197,154],{"class":57},[38,2199,2015],{"class":65},[38,2201,2202],{"class":40,"line":184},[38,2203,181],{"emptyLinePlaceholder":180},[38,2205,2206],{"class":40,"line":190},[38,2207,2024],{"class":44},[38,2209,2210,2212,2214,2216],{"class":40,"line":204},[38,2211,111],{"class":57},[38,2213,2031],{"class":65},[38,2215,117],{"class":57},[38,2217,1994],{"class":65},[38,2219,2220,2222,2224,2226,2228,2230],{"class":40,"line":210},[38,2221,882],{"class":57},[38,2223,891],{"class":81},[38,2225,2044],{"class":65},[38,2227,263],{"class":57},[38,2229,2049],{"class":81},[38,2231,66],{"class":65},[38,2233,2234],{"class":40,"line":224},[38,2235,2236],{"class":57},"                continue\n",[38,2238,2239],{"class":40,"line":241},[38,2240,181],{"emptyLinePlaceholder":180},[38,2242,2243,2246,2248,2250,2252],{"class":40,"line":255},[38,2244,2245],{"class":65},"            first ",[38,2247,154],{"class":57},[38,2249,2055],{"class":65},[38,2251,235],{"class":81},[38,2253,174],{"class":65},[38,2255,2256,2259,2261,2263,2265],{"class":40,"line":277},[38,2257,2258],{"class":65},"            second ",[38,2260,154],{"class":57},[38,2262,2055],{"class":65},[38,2264,160],{"class":81},[38,2266,174],{"class":65},[38,2268,2269,2272,2274,2277,2279],{"class":40,"line":294},[38,2270,2271],{"class":65},"            gap ",[38,2273,154],{"class":57},[38,2275,2276],{"class":65}," first ",[38,2278,269],{"class":57},[38,2280,2281],{"class":65}," second\n",[38,2283,2284,2287,2289],{"class":40,"line":302},[38,2285,2286],{"class":65},"            fail ",[38,2288,154],{"class":57},[38,2290,2291],{"class":81}," False\n",[38,2293,2294],{"class":40,"line":312},[38,2295,2296],{"class":44},"            # print(seen[key][2:])\n",[38,2298,2299,2301,2303,2305,2307,2309],{"class":40,"line":317},[38,2300,135],{"class":57},[38,2302,843],{"class":65},[38,2304,117],{"class":57},[38,2306,2055],{"class":65},[38,2308,2058],{"class":81},[38,2310,2311],{"class":65},":]:\n",[38,2313,2314],{"class":40,"line":322},[38,2315,2316],{"class":44},"                # print(second, num, gap)\n",[38,2318,2319,2321,2324,2327,2330,2332],{"class":40,"line":798},[38,2320,1122],{"class":57},[38,2322,2323],{"class":65}," gap ",[38,2325,2326],{"class":57},"!=",[38,2328,2329],{"class":65}," second ",[38,2331,269],{"class":57},[38,2333,2334],{"class":65}," num:\n",[38,2336,2337,2340,2342],{"class":40,"line":807},[38,2338,2339],{"class":65},"                    fail ",[38,2341,154],{"class":57},[38,2343,2344],{"class":81}," True\n",[38,2346,2347],{"class":40,"line":827},[38,2348,1152],{"class":57},[38,2350,2351,2354],{"class":40,"line":838},[38,2352,2353],{"class":57},"                else",[38,2355,66],{"class":65},[38,2357,2358,2361,2363],{"class":40,"line":851},[38,2359,2360],{"class":65},"                    second ",[38,2362,154],{"class":57},[38,2364,2365],{"class":65}," num\n",[38,2367,2368,2370],{"class":40,"line":868},[38,2369,882],{"class":57},[38,2371,2372],{"class":65}," fail:\n",[38,2374,2375],{"class":40,"line":879},[38,2376,2236],{"class":57},[38,2378,2379,2381],{"class":40,"line":897},[38,2380,1380],{"class":57},[38,2382,66],{"class":65},[38,2384,2385,2387,2389],{"class":40,"line":915},[38,2386,1171],{"class":65},[38,2388,974],{"class":57},[38,2390,912],{"class":81},[38,2392,2393,2395],{"class":40,"line":929},[38,2394,325],{"class":57},[38,2396,1182],{"class":65},[11,2398,994,2399],{},[15,2400,2403],{"href":2401,"rel":2402},"https://leetcode.com/problems/minimum-days-to-score-exactly-n-points/",[19],"Minimum Days to Score Exactly N Points",[11,2405,2406],{},"題目定義每天可以選擇累加或是休息，來湊出 target number",[22,2408,2409],{},[11,2410,2411],{},"原始思路：是先把可以用的選項算出來，然後透過 DP Array 求出達到target number 所需最少的天數",[28,2413,2415],{"className":30,"code":2414,"language":32,"meta":33,"style":33},"class Solution:\n    def minDays(self, n: int) -> int:\n        options = []\n        cal = 0\n        i = 0\n        while cal \u003C= n:\n            i += 1\n            cal = (1 + i) * i // 2\n            if cal > n:\n                break\n            options.append(cal)\n\n        dp = [float(\"inf\")] * (n+1)\n        dp[0] = 0\n\n        for i in range(1, n + 1):\n            for j in range(len(options)):\n                if i - options[j] >= 0:\n                    if i - options[j] != 0 and dp[i - options[j]] != float(\"inf\"):\n                        dp[i] = min(dp[i], dp[i - options[j]] + j + 1 + 1)\n                    else:\n                        dp[i] = min(dp[i], dp[i - options[j]] + j + 1)\n                else:\n                    break\n        return dp[-1]\n",[35,2416,2417,2425,2443,2453,2462,2471,2484,2493,2519,2529,2534,2539,2543,2575,2588,2592,2615,2633,2650,2684,2714,2720,2744,2750,2754],{"__ignoreMap":33},[38,2418,2419,2421,2423],{"class":40,"line":41},[38,2420,58],{"class":57},[38,2422,62],{"class":61},[38,2424,66],{"class":65},[38,2426,2427,2429,2432,2434,2436,2439,2441],{"class":40,"line":48},[38,2428,72],{"class":57},[38,2430,2431],{"class":61}," minDays",[38,2433,78],{"class":65},[38,2435,82],{"class":81},[38,2437,2438],{"class":65},") -> ",[38,2440,82],{"class":81},[38,2442,66],{"class":65},[38,2444,2445,2448,2450],{"class":40,"line":54},[38,2446,2447],{"class":65},"        options ",[38,2449,154],{"class":57},[38,2451,2452],{"class":65}," []\n",[38,2454,2455,2458,2460],{"class":40,"line":69},[38,2456,2457],{"class":65},"        cal ",[38,2459,154],{"class":57},[38,2461,835],{"class":81},[38,2463,2464,2467,2469],{"class":40,"line":108},[38,2465,2466],{"class":65},"        i ",[38,2468,154],{"class":57},[38,2470,835],{"class":81},[38,2472,2473,2476,2479,2481],{"class":40,"line":126},[38,2474,2475],{"class":57},"        while",[38,2477,2478],{"class":65}," cal ",[38,2480,1127],{"class":57},[38,2482,2483],{"class":65}," n:\n",[38,2485,2486,2489,2491],{"class":40,"line":132},[38,2487,2488],{"class":65},"            i ",[38,2490,974],{"class":57},[38,2492,912],{"class":81},[38,2494,2495,2498,2500,2503,2505,2508,2511,2513,2515,2517],{"class":40,"line":148},[38,2496,2497],{"class":65},"            cal ",[38,2499,154],{"class":57},[38,2501,2502],{"class":65}," (",[38,2504,160],{"class":81},[38,2506,2507],{"class":57}," +",[38,2509,2510],{"class":65}," i) ",[38,2512,403],{"class":57},[38,2514,114],{"class":65},[38,2516,980],{"class":57},[38,2518,983],{"class":81},[38,2520,2521,2523,2525,2527],{"class":40,"line":177},[38,2522,882],{"class":57},[38,2524,2478],{"class":65},[38,2526,1299],{"class":57},[38,2528,2483],{"class":65},[38,2530,2531],{"class":40,"line":184},[38,2532,2533],{"class":57},"                break\n",[38,2535,2536],{"class":40,"line":190},[38,2537,2538],{"class":65},"            options.append(cal)\n",[38,2540,2541],{"class":40,"line":204},[38,2542,181],{"emptyLinePlaceholder":180},[38,2544,2545,2548,2550,2553,2556,2558,2561,2564,2566,2569,2571,2573],{"class":40,"line":210},[38,2546,2547],{"class":65},"        dp ",[38,2549,154],{"class":57},[38,2551,2552],{"class":65}," [",[38,2554,2555],{"class":81},"float",[38,2557,608],{"class":65},[38,2559,2560],{"class":1620},"\"inf\"",[38,2562,2563],{"class":65},")] ",[38,2565,403],{"class":57},[38,2567,2568],{"class":65}," (n",[38,2570,166],{"class":57},[38,2572,160],{"class":81},[38,2574,1457],{"class":65},[38,2576,2577,2580,2582,2584,2586],{"class":40,"line":224},[38,2578,2579],{"class":65},"        dp[",[38,2581,235],{"class":81},[38,2583,400],{"class":65},[38,2585,154],{"class":57},[38,2587,835],{"class":81},[38,2589,2590],{"class":40,"line":241},[38,2591,181],{"emptyLinePlaceholder":180},[38,2593,2594,2596,2598,2600,2602,2604,2606,2609,2611,2613],{"class":40,"line":255},[38,2595,111],{"class":57},[38,2597,114],{"class":65},[38,2599,117],{"class":57},[38,2601,120],{"class":81},[38,2603,608],{"class":65},[38,2605,160],{"class":81},[38,2607,2608],{"class":65},", n ",[38,2610,166],{"class":57},[38,2612,272],{"class":81},[38,2614,619],{"class":65},[38,2616,2617,2619,2621,2623,2625,2627,2630],{"class":40,"line":277},[38,2618,135],{"class":57},[38,2620,195],{"class":65},[38,2622,117],{"class":57},[38,2624,120],{"class":81},[38,2626,608],{"class":65},[38,2628,2629],{"class":81},"len",[38,2631,2632],{"class":65},"(options)):\n",[38,2634,2635,2637,2639,2641,2644,2646,2648],{"class":40,"line":294},[38,2636,1122],{"class":57},[38,2638,114],{"class":65},[38,2640,269],{"class":57},[38,2642,2643],{"class":65}," options[j] ",[38,2645,888],{"class":57},[38,2647,1239],{"class":81},[38,2649,66],{"class":65},[38,2651,2652,2654,2656,2658,2660,2662,2664,2666,2669,2671,2674,2676,2678,2680,2682],{"class":40,"line":302},[38,2653,258],{"class":57},[38,2655,114],{"class":65},[38,2657,269],{"class":57},[38,2659,2643],{"class":65},[38,2661,2326],{"class":57},[38,2663,1239],{"class":81},[38,2665,2052],{"class":57},[38,2667,2668],{"class":65}," dp[i ",[38,2670,269],{"class":57},[38,2672,2673],{"class":65}," options[j]] ",[38,2675,2326],{"class":57},[38,2677,1615],{"class":81},[38,2679,608],{"class":65},[38,2681,2560],{"class":1620},[38,2683,619],{"class":65},[38,2685,2686,2689,2691,2693,2696,2698,2700,2702,2704,2706,2708,2710,2712],{"class":40,"line":312},[38,2687,2688],{"class":65},"                        dp[i] ",[38,2690,154],{"class":57},[38,2692,923],{"class":81},[38,2694,2695],{"class":65},"(dp[i], dp[i ",[38,2697,269],{"class":57},[38,2699,2673],{"class":65},[38,2701,166],{"class":57},[38,2703,195],{"class":65},[38,2705,166],{"class":57},[38,2707,272],{"class":81},[38,2709,2507],{"class":57},[38,2711,272],{"class":81},[38,2713,1457],{"class":65},[38,2715,2716,2718],{"class":40,"line":317},[38,2717,297],{"class":57},[38,2719,66],{"class":65},[38,2721,2722,2724,2726,2728,2730,2732,2734,2736,2738,2740,2742],{"class":40,"line":322},[38,2723,2688],{"class":65},[38,2725,154],{"class":57},[38,2727,923],{"class":81},[38,2729,2695],{"class":65},[38,2731,269],{"class":57},[38,2733,2673],{"class":65},[38,2735,166],{"class":57},[38,2737,195],{"class":65},[38,2739,166],{"class":57},[38,2741,272],{"class":81},[38,2743,1457],{"class":65},[38,2745,2746,2748],{"class":40,"line":798},[38,2747,2353],{"class":57},[38,2749,66],{"class":65},[38,2751,2752],{"class":40,"line":807},[38,2753,1152],{"class":57},[38,2755,2756,2758,2761,2763,2765],{"class":40,"line":827},[38,2757,325],{"class":57},[38,2759,2760],{"class":65}," dp[",[38,2762,269],{"class":57},[38,2764,160],{"class":81},[38,2766,174],{"class":65},[11,2768,2769,2770],{},"Q4\n沒寫出來\n",[15,2771,2774],{"href":2772,"rel":2773},"https://leetcode.com/problems/count-subarrays-with-distant-sums/",[19],"Count Subarrays with Distant Sums",[22,2776,2777],{},[11,2778,2779],{},"原始思路：一頭霧水，大概知道要用 prefix sum 去節省每次計算 sum 的時間，但完全不知道如何具體實作",[22,2781,2782],{},[11,2783,2784],{},"最佳解：比想像中還複雜：",[11,2786,2787],{},"題目要求計算哪些 subarray 滿足總和超過 goal 至少 k",[11,2789,2790],{},"直接數「distant」不好算。反過來數「non-distant」比較簡單，我們可以透過以下方法來知道 non-distant 的條件",[508,2792,2793,2799,2810],{},[511,2794,2795,2796],{},"Distant 條件： ",[35,2797,2798],{},"|sum - goal| >= k",[511,2800,2801,2802,2805,2806,2809],{},"Non-distant 條件： ",[35,2803,2804],{},"goal-k \u003C sum \u003C goal+k","（整數就是 ",[35,2807,2808],{},"[goal-k+1, goal+k-1]","）",[511,2811,2812],{},"答案 = 全部子陣列數 − non-distant 數量",[28,2814,2816],{"className":30,"code":2815,"language":32,"meta":33,"style":33},"class Solution:\n    def countSubarrays(self, nums: list[int], goal: int, k: int) -> int:\n        size = len(nums)\n        total_subarrays = size * (size + 1) // 2\n        if k == 0:\n            return total_subarrays\n\n        prefix_sum = [0] * (size + 1)\n        for idx in range(size):\n            prefix_sum[idx + 1] = prefix_sum[idx] + nums[idx]\n\n        def count_pairs_with_diff_at_most(threshold: int) -> int:\n            \"\"\"Count pairs (earlier, later) where prefix_sum[later] - prefix_sum[earlier] \u003C= threshold.\"\"\"\n            sorted_copy = list(prefix_sum)\n            merge_buffer = [0] * (size + 1)\n\n            def merge_and_count(left_start: int, right_end: int) -> int:\n                if right_end - left_start \u003C= 1:\n                    return 0\n                mid = (left_start + right_end) // 2\n                count = merge_and_count(left_start, mid) + merge_and_count(mid, right_end)\n\n                scan = left_start\n                for right_idx in range(mid, right_end):\n                    while scan \u003C mid and sorted_copy[scan] \u003C sorted_copy[right_idx] - threshold:\n                        scan += 1\n                    count += mid - scan\n\n                write_pos = left_start\n                left_idx, right_idx = left_start, mid\n                while left_idx \u003C mid and right_idx \u003C right_end:\n                    if sorted_copy[left_idx] \u003C= sorted_copy[right_idx]:\n                        merge_buffer[write_pos] = sorted_copy[left_idx]\n                        left_idx += 1\n                    else:\n                        merge_buffer[write_pos] = sorted_copy[right_idx]\n                        right_idx += 1\n                    write_pos += 1\n                while left_idx \u003C mid:\n                    merge_buffer[write_pos] = sorted_copy[left_idx]\n                    left_idx += 1; write_pos += 1\n                while right_idx \u003C right_end:\n                    merge_buffer[write_pos] = sorted_copy[right_idx]\n                    right_idx += 1; write_pos += 1\n                sorted_copy[left_start:right_end] = merge_buffer[left_start:right_end]\n                return count\n\n            return merge_and_count(0, size + 1)\n\n        upper = goal + k - 1\n        lower = goal - k\n        non_distant_count = (\n            count_pairs_with_diff_at_most(upper)\n            - count_pairs_with_diff_at_most(lower)\n        )\n        return total_subarrays - non_distant_count\n",[35,2817,2818,2826,2853,2864,2890,2904,2912,2916,2939,2952,2973,2977,2996,3001,3014,3037,3041,3065,3083,3090,3109,3123,3127,3137,3151,3179,3188,3202,3206,3215,3225,3246,3258,3268,3277,3283,3292,3302,3312,3324,3334,3351,3362,3371,3387,3398,3407,3412,3431,3436,3455,3470,3481,3487,3496,3502],{"__ignoreMap":33},[38,2819,2820,2822,2824],{"class":40,"line":41},[38,2821,58],{"class":57},[38,2823,62],{"class":61},[38,2825,66],{"class":65},[38,2827,2828,2830,2833,2835,2837,2840,2842,2845,2847,2849,2851],{"class":40,"line":48},[38,2829,72],{"class":57},[38,2831,2832],{"class":61}," countSubarrays",[38,2834,815],{"class":65},[38,2836,82],{"class":81},[38,2838,2839],{"class":65},"], goal: ",[38,2841,82],{"class":81},[38,2843,2844],{"class":65},", k: ",[38,2846,82],{"class":81},[38,2848,2438],{"class":65},[38,2850,82],{"class":81},[38,2852,66],{"class":65},[38,2854,2855,2858,2860,2862],{"class":40,"line":54},[38,2856,2857],{"class":65},"        size ",[38,2859,154],{"class":57},[38,2861,891],{"class":81},[38,2863,1084],{"class":65},[38,2865,2866,2869,2871,2874,2876,2879,2881,2883,2886,2888],{"class":40,"line":69},[38,2867,2868],{"class":65},"        total_subarrays ",[38,2870,154],{"class":57},[38,2872,2873],{"class":65}," size ",[38,2875,403],{"class":57},[38,2877,2878],{"class":65}," (size ",[38,2880,166],{"class":57},[38,2882,272],{"class":81},[38,2884,2885],{"class":65},") ",[38,2887,980],{"class":57},[38,2889,983],{"class":81},[38,2891,2892,2895,2898,2900,2902],{"class":40,"line":108},[38,2893,2894],{"class":57},"        if",[38,2896,2897],{"class":65}," k ",[38,2899,1349],{"class":57},[38,2901,1239],{"class":81},[38,2903,66],{"class":65},[38,2905,2906,2909],{"class":40,"line":126},[38,2907,2908],{"class":57},"            return",[38,2910,2911],{"class":65}," total_subarrays\n",[38,2913,2914],{"class":40,"line":132},[38,2915,181],{"emptyLinePlaceholder":180},[38,2917,2918,2921,2923,2925,2927,2929,2931,2933,2935,2937],{"class":40,"line":148},[38,2919,2920],{"class":65},"        prefix_sum ",[38,2922,154],{"class":57},[38,2924,2552],{"class":65},[38,2926,235],{"class":81},[38,2928,400],{"class":65},[38,2930,403],{"class":57},[38,2932,2878],{"class":65},[38,2934,166],{"class":57},[38,2936,272],{"class":81},[38,2938,1457],{"class":65},[38,2940,2941,2943,2945,2947,2949],{"class":40,"line":177},[38,2942,111],{"class":57},[38,2944,885],{"class":65},[38,2946,117],{"class":57},[38,2948,120],{"class":81},[38,2950,2951],{"class":65},"(size):\n",[38,2953,2954,2957,2959,2961,2963,2965,2968,2970],{"class":40,"line":184},[38,2955,2956],{"class":65},"            prefix_sum[idx ",[38,2958,166],{"class":57},[38,2960,272],{"class":81},[38,2962,400],{"class":65},[38,2964,154],{"class":57},[38,2966,2967],{"class":65}," prefix_sum[idx] ",[38,2969,166],{"class":57},[38,2971,2972],{"class":65}," nums[idx]\n",[38,2974,2975],{"class":40,"line":190},[38,2976,181],{"emptyLinePlaceholder":180},[38,2978,2979,2982,2985,2988,2990,2992,2994],{"class":40,"line":204},[38,2980,2981],{"class":57},"        def",[38,2983,2984],{"class":61}," count_pairs_with_diff_at_most",[38,2986,2987],{"class":65},"(threshold: ",[38,2989,82],{"class":81},[38,2991,2438],{"class":65},[38,2993,82],{"class":81},[38,2995,66],{"class":65},[38,2997,2998],{"class":40,"line":210},[38,2999,3000],{"class":1620},"            \"\"\"Count pairs (earlier, later) where prefix_sum[later] - prefix_sum[earlier] \u003C= threshold.\"\"\"\n",[38,3002,3003,3006,3008,3011],{"class":40,"line":224},[38,3004,3005],{"class":65},"            sorted_copy ",[38,3007,154],{"class":57},[38,3009,3010],{"class":81}," list",[38,3012,3013],{"class":65},"(prefix_sum)\n",[38,3015,3016,3019,3021,3023,3025,3027,3029,3031,3033,3035],{"class":40,"line":241},[38,3017,3018],{"class":65},"            merge_buffer ",[38,3020,154],{"class":57},[38,3022,2552],{"class":65},[38,3024,235],{"class":81},[38,3026,400],{"class":65},[38,3028,403],{"class":57},[38,3030,2878],{"class":65},[38,3032,166],{"class":57},[38,3034,272],{"class":81},[38,3036,1457],{"class":65},[38,3038,3039],{"class":40,"line":255},[38,3040,181],{"emptyLinePlaceholder":180},[38,3042,3043,3046,3049,3052,3054,3057,3059,3061,3063],{"class":40,"line":277},[38,3044,3045],{"class":57},"            def",[38,3047,3048],{"class":61}," merge_and_count",[38,3050,3051],{"class":65},"(left_start: ",[38,3053,82],{"class":81},[38,3055,3056],{"class":65},", right_end: ",[38,3058,82],{"class":81},[38,3060,2438],{"class":65},[38,3062,82],{"class":81},[38,3064,66],{"class":65},[38,3066,3067,3069,3072,3074,3077,3079,3081],{"class":40,"line":294},[38,3068,1122],{"class":57},[38,3070,3071],{"class":65}," right_end ",[38,3073,269],{"class":57},[38,3075,3076],{"class":65}," left_start ",[38,3078,1127],{"class":57},[38,3080,272],{"class":81},[38,3082,66],{"class":65},[38,3084,3085,3088],{"class":40,"line":302},[38,3086,3087],{"class":57},"                    return",[38,3089,835],{"class":81},[38,3091,3092,3095,3097,3100,3102,3105,3107],{"class":40,"line":312},[38,3093,3094],{"class":65},"                mid ",[38,3096,154],{"class":57},[38,3098,3099],{"class":65}," (left_start ",[38,3101,166],{"class":57},[38,3103,3104],{"class":65}," right_end) ",[38,3106,980],{"class":57},[38,3108,983],{"class":81},[38,3110,3111,3113,3115,3118,3120],{"class":40,"line":317},[38,3112,1861],{"class":65},[38,3114,154],{"class":57},[38,3116,3117],{"class":65}," merge_and_count(left_start, mid) ",[38,3119,166],{"class":57},[38,3121,3122],{"class":65}," merge_and_count(mid, right_end)\n",[38,3124,3125],{"class":40,"line":322},[38,3126,181],{"emptyLinePlaceholder":180},[38,3128,3129,3132,3134],{"class":40,"line":798},[38,3130,3131],{"class":65},"                scan ",[38,3133,154],{"class":57},[38,3135,3136],{"class":65}," left_start\n",[38,3138,3139,3141,3144,3146,3148],{"class":40,"line":807},[38,3140,244],{"class":57},[38,3142,3143],{"class":65}," right_idx ",[38,3145,117],{"class":57},[38,3147,120],{"class":81},[38,3149,3150],{"class":65},"(mid, right_end):\n",[38,3152,3153,3156,3159,3161,3164,3166,3169,3171,3174,3176],{"class":40,"line":827},[38,3154,3155],{"class":57},"                    while",[38,3157,3158],{"class":65}," scan ",[38,3160,263],{"class":57},[38,3162,3163],{"class":65}," mid ",[38,3165,1282],{"class":57},[38,3167,3168],{"class":65}," sorted_copy[scan] ",[38,3170,263],{"class":57},[38,3172,3173],{"class":65}," sorted_copy[right_idx] ",[38,3175,269],{"class":57},[38,3177,3178],{"class":65}," threshold:\n",[38,3180,3181,3184,3186],{"class":40,"line":838},[38,3182,3183],{"class":65},"                        scan ",[38,3185,974],{"class":57},[38,3187,912],{"class":81},[38,3189,3190,3193,3195,3197,3199],{"class":40,"line":851},[38,3191,3192],{"class":65},"                    count ",[38,3194,974],{"class":57},[38,3196,3163],{"class":65},[38,3198,269],{"class":57},[38,3200,3201],{"class":65}," scan\n",[38,3203,3204],{"class":40,"line":868},[38,3205,181],{"emptyLinePlaceholder":180},[38,3207,3208,3211,3213],{"class":40,"line":879},[38,3209,3210],{"class":65},"                write_pos ",[38,3212,154],{"class":57},[38,3214,3136],{"class":65},[38,3216,3217,3220,3222],{"class":40,"line":897},[38,3218,3219],{"class":65},"                left_idx, right_idx ",[38,3221,154],{"class":57},[38,3223,3224],{"class":65}," left_start, mid\n",[38,3226,3227,3230,3233,3235,3237,3239,3241,3243],{"class":40,"line":915},[38,3228,3229],{"class":57},"                while",[38,3231,3232],{"class":65}," left_idx ",[38,3234,263],{"class":57},[38,3236,3163],{"class":65},[38,3238,1282],{"class":57},[38,3240,3143],{"class":65},[38,3242,263],{"class":57},[38,3244,3245],{"class":65}," right_end:\n",[38,3247,3248,3250,3253,3255],{"class":40,"line":929},[38,3249,258],{"class":57},[38,3251,3252],{"class":65}," sorted_copy[left_idx] ",[38,3254,1127],{"class":57},[38,3256,3257],{"class":65}," sorted_copy[right_idx]:\n",[38,3259,3260,3263,3265],{"class":40,"line":943},[38,3261,3262],{"class":65},"                        merge_buffer[write_pos] ",[38,3264,154],{"class":57},[38,3266,3267],{"class":65}," sorted_copy[left_idx]\n",[38,3269,3270,3273,3275],{"class":40,"line":962},[38,3271,3272],{"class":65},"                        left_idx ",[38,3274,974],{"class":57},[38,3276,912],{"class":81},[38,3278,3279,3281],{"class":40,"line":968},[38,3280,297],{"class":57},[38,3282,66],{"class":65},[38,3284,3285,3287,3289],{"class":40,"line":986},[38,3286,3262],{"class":65},[38,3288,154],{"class":57},[38,3290,3291],{"class":65}," sorted_copy[right_idx]\n",[38,3293,3295,3298,3300],{"class":40,"line":3294},37,[38,3296,3297],{"class":65},"                        right_idx ",[38,3299,974],{"class":57},[38,3301,912],{"class":81},[38,3303,3305,3308,3310],{"class":40,"line":3304},38,[38,3306,3307],{"class":65},"                    write_pos ",[38,3309,974],{"class":57},[38,3311,912],{"class":81},[38,3313,3315,3317,3319,3321],{"class":40,"line":3314},39,[38,3316,3229],{"class":57},[38,3318,3232],{"class":65},[38,3320,263],{"class":57},[38,3322,3323],{"class":65}," mid:\n",[38,3325,3327,3330,3332],{"class":40,"line":3326},40,[38,3328,3329],{"class":65},"                    merge_buffer[write_pos] ",[38,3331,154],{"class":57},[38,3333,3267],{"class":65},[38,3335,3337,3340,3342,3344,3347,3349],{"class":40,"line":3336},41,[38,3338,3339],{"class":65},"                    left_idx ",[38,3341,974],{"class":57},[38,3343,272],{"class":81},[38,3345,3346],{"class":65},"; write_pos ",[38,3348,974],{"class":57},[38,3350,912],{"class":81},[38,3352,3354,3356,3358,3360],{"class":40,"line":3353},42,[38,3355,3229],{"class":57},[38,3357,3143],{"class":65},[38,3359,263],{"class":57},[38,3361,3245],{"class":65},[38,3363,3365,3367,3369],{"class":40,"line":3364},43,[38,3366,3329],{"class":65},[38,3368,154],{"class":57},[38,3370,3291],{"class":65},[38,3372,3374,3377,3379,3381,3383,3385],{"class":40,"line":3373},44,[38,3375,3376],{"class":65},"                    right_idx ",[38,3378,974],{"class":57},[38,3380,272],{"class":81},[38,3382,3346],{"class":65},[38,3384,974],{"class":57},[38,3386,912],{"class":81},[38,3388,3390,3393,3395],{"class":40,"line":3389},45,[38,3391,3392],{"class":65},"                sorted_copy[left_start:right_end] ",[38,3394,154],{"class":57},[38,3396,3397],{"class":65}," merge_buffer[left_start:right_end]\n",[38,3399,3401,3404],{"class":40,"line":3400},46,[38,3402,3403],{"class":57},"                return",[38,3405,3406],{"class":65}," count\n",[38,3408,3410],{"class":40,"line":3409},47,[38,3411,181],{"emptyLinePlaceholder":180},[38,3413,3415,3417,3420,3422,3425,3427,3429],{"class":40,"line":3414},48,[38,3416,2908],{"class":57},[38,3418,3419],{"class":65}," merge_and_count(",[38,3421,235],{"class":81},[38,3423,3424],{"class":65},", size ",[38,3426,166],{"class":57},[38,3428,272],{"class":81},[38,3430,1457],{"class":65},[38,3432,3434],{"class":40,"line":3433},49,[38,3435,181],{"emptyLinePlaceholder":180},[38,3437,3439,3442,3444,3447,3449,3451,3453],{"class":40,"line":3438},50,[38,3440,3441],{"class":65},"        upper ",[38,3443,154],{"class":57},[38,3445,3446],{"class":65}," goal ",[38,3448,166],{"class":57},[38,3450,2897],{"class":65},[38,3452,269],{"class":57},[38,3454,912],{"class":81},[38,3456,3458,3461,3463,3465,3467],{"class":40,"line":3457},51,[38,3459,3460],{"class":65},"        lower ",[38,3462,154],{"class":57},[38,3464,3446],{"class":65},[38,3466,269],{"class":57},[38,3468,3469],{"class":65}," k\n",[38,3471,3473,3476,3478],{"class":40,"line":3472},52,[38,3474,3475],{"class":65},"        non_distant_count ",[38,3477,154],{"class":57},[38,3479,3480],{"class":65}," (\n",[38,3482,3484],{"class":40,"line":3483},53,[38,3485,3486],{"class":65},"            count_pairs_with_diff_at_most(upper)\n",[38,3488,3490,3493],{"class":40,"line":3489},54,[38,3491,3492],{"class":57},"            -",[38,3494,3495],{"class":65}," count_pairs_with_diff_at_most(lower)\n",[38,3497,3499],{"class":40,"line":3498},55,[38,3500,3501],{"class":65},"        )\n",[38,3503,3505,3507,3510,3512],{"class":40,"line":3504},56,[38,3506,325],{"class":57},[38,3508,3509],{"class":65}," total_subarrays ",[38,3511,269],{"class":57},[38,3513,3514],{"class":65}," non_distant_count\n",[1882,3516,3517],{},"html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}",{"title":33,"searchDepth":48,"depth":48,"links":3519},[],"Biweekly Contest 191 過程思路與心得",{},"/blog/leetcode-contest/leetcode-biweekly-191",{"title":1906,"description":3520},"blog/Leetcode Contest/leetcode-biweekly-191",[1897,1898,1899,1900],"SKR-x3lJV2WMUITpWbZ2MVMWQefxCIhMhEh_NBoQI0g",{"id":3528,"title":3529,"author":6,"body":3530,"category":1887,"date":5622,"description":5623,"extension":1890,"image":33,"language":1891,"meta":5624,"navigation":180,"path":5625,"seo":5626,"stem":5627,"tags":5628,"updatedAt":1901,"__hash__":5631},"blog/blog/concurrency.md","Python 並發處理方法",{"type":8,"value":3531,"toc":5601},[3532,3537,3540,3543,3546,3551,3599,3603,3638,3642,3675,3679,3697,3700,3848,3851,5177,5180,5428,5432,5438,5456,5460,5465,5483,5486,5491,5495,5498,5502,5505,5519,5523,5526,5572,5575,5598],[3533,3534,3536],"h2",{"id":3535},"這篇文章的用處","這篇文章的用處？",[11,3538,3539],{},"若專案內有遇到效能瓶頸，這可能可以幫助你加速。",[11,3541,3542],{},"Python 提供了幾種並發方式，每種方式適用於不同類型的任務。",[3533,3544,3545],{"id":3545},"各方式介紹",[3547,3548,3550],"h3",{"id":3549},"_1-多線程multithreading","1. 多線程（Multithreading）",[508,3552,3553,3560,3581,3587,3593],{},[511,3554,3555,3559],{},[3556,3557,3558],"strong",{},"特點","：由於 GIL 的存在，多線程無法實現真正的並行，線程間由解釋器切換執行。",[511,3561,3562,3565,3566,3569,3570],{},[3556,3563,3564],{},"適用場景","：適合 ",[3556,3567,3568],{},"I/O 綁定任務","，如：\n",[508,3571,3572,3575,3578],{},[511,3573,3574],{},"API 呼叫",[511,3576,3577],{},"檔案讀寫",[511,3579,3580],{},"使用者輸入等待",[511,3582,3583,3586],{},[3556,3584,3585],{},"限制","：在 CPU 綁定任務（如計算 Fibonacci 數列）中，效能與單線程迴圈相差無幾。",[511,3588,3589,3592],{},[3556,3590,3591],{},"優點","：線程間資料共享簡單，記憶體開銷低。",[511,3594,3595,3598],{},[3556,3596,3597],{},"缺點","：受 GIL 限制，無法利用多核心。",[3547,3600,3602],{"id":3601},"_2-多進程multiprocessing","2. 多進程（Multiprocessing）",[508,3604,3605,3610,3628,3633],{},[511,3606,3607,3609],{},[3556,3608,3558],{},"：每個進程擁有獨立的 Python 解釋器和 GIL，因此可以在不同 CPU 核心上實現真正的並行。",[511,3611,3612,3565,3614,3569,3617],{},[3556,3613,3564],{},[3556,3615,3616],{},"CPU 綁定任務",[508,3618,3619,3622,3625],{},[511,3620,3621],{},"數學運算",[511,3623,3624],{},"圖像處理",[511,3626,3627],{},"日誌分析",[511,3629,3630,3632],{},[3556,3631,3591],{},"：繞過 GIL，實現真並行，速度較快。",[511,3634,3635,3637],{},[3556,3636,3597],{},"：記憶體使用量高，進程間資料共享較複雜（需使用管道或共享記憶體）。",[3547,3639,3641],{"id":3640},"_3-asyncio","3. Asyncio",[508,3643,3644,3649,3665,3670],{},[511,3645,3646,3648],{},[3556,3647,3558],{},"：使用協程（coroutines）實現非阻塞的並發，適合 I/O 綁定任務。",[511,3650,3651,3653,3654],{},[3556,3652,3564],{},"：\n",[508,3655,3656,3659,3662],{},[511,3657,3658],{},"網路請求",[511,3660,3661],{},"檔案 I/O",[511,3663,3664],{},"其他等待外部資源的任務",[511,3666,3667,3669],{},[3556,3668,3591],{},"：輕量，記憶體使用效率高。",[511,3671,3672,3674],{},[3556,3673,3597],{},"：不適合 CPU 密集型任務，因為它並非真正的並行。",[3547,3676,3678],{"id":3677},"_4-第三方庫","4. 第三方庫",[508,3680,3681,3687,3692],{},[511,3682,3683,3686],{},[3556,3684,3685],{},"例子","：Cython、NumPy、Pandas、PyTorch 等。",[511,3688,3689,3691],{},[3556,3690,3558],{},"：這些庫通常使用 C 語言實現，部分操作可繞過 GIL，提供高效能。",[511,3693,3694,3696],{},[3556,3695,3564],{},"：特定計算密集型任務（如矩陣運算）。",[3533,3698,3699],{"id":3699},"特性比較表",[3701,3702,3703,3725],"table",{},[3704,3705,3706],"thead",{},[3707,3708,3709,3713,3716,3719,3722],"tr",{},[3710,3711,3712],"th",{},"特性",[3710,3714,3715],{},"Multi-threading",[3710,3717,3718],{},"Multi-processing",[3710,3720,3721],{},"AsyncIO",[3710,3723,3724],{},"Disabled GIL",[3726,3727,3728,3746,3763,3781,3798,3814,3829],"tbody",{},[3707,3729,3730,3736,3739,3742,3744],{},[3731,3732,3733],"td",{},[3556,3734,3735],{},"並行",[3731,3737,3738],{},"❌",[3731,3740,3741],{},"✅",[3731,3743,3738],{},[3731,3745,3741],{},[3707,3747,3748,3753,3756,3759,3761],{},[3731,3749,3750],{},[3556,3751,3752],{},"記憶體共享",[3731,3754,3755],{},"容易",[3731,3757,3758],{},"困難",[3731,3760,3755],{},[3731,3762,3755],{},[3707,3764,3765,3770,3773,3776,3778],{},[3731,3766,3767],{},[3556,3768,3769],{},"記憶體使用",[3731,3771,3772],{},"低",[3731,3774,3775],{},"高",[3731,3777,3772],{},[3731,3779,3780],{},"中等",[3707,3782,3783,3788,3791,3794,3796],{},[3731,3784,3785],{},[3556,3786,3787],{},"CPU 密集型",[3731,3789,3790],{},"差",[3731,3792,3793],{},"好",[3731,3795,3790],{},[3731,3797,3793],{},[3707,3799,3800,3805,3807,3809,3812],{},[3731,3801,3802],{},[3556,3803,3804],{},"I/O 密集型",[3731,3806,3793],{},[3731,3808,3780],{},[3731,3810,3811],{},"最佳",[3731,3813,3793],{},[3707,3815,3816,3821,3823,3825,3827],{},[3731,3817,3818],{},[3556,3819,3820],{},"實作複雜度",[3731,3822,3780],{},[3731,3824,3775],{},[3731,3826,3780],{},[3731,3828,3775],{},[3707,3830,3831,3836,3839,3842,3845],{},[3731,3832,3833],{},[3556,3834,3835],{},"競爭條件風險",[3731,3837,3838],{},"低（GIL保護）",[3731,3840,3841],{},"低（隔離）",[3731,3843,3844],{},"無（單執行緒）",[3731,3846,3847],{},"高（需手動處理）",[3533,3849,3850],{"id":3850},"範例程式碼",[28,3852,3854],{"className":30,"code":3853,"language":32,"meta":33,"style":33},"import time\nimport threading\nimport multiprocessing\nimport asyncio\nimport sys\nfrom concurrent.futures import ThreadPoolExecutor\nfrom functools import wraps\n\n# 計時裝飾器，用於測量執行時間\ndef timing_decorator(func):\n    @wraps(func)\n    def wrapper(*args, **kwargs):\n        start = time.time()\n        result = func(*args, **kwargs)\n        end = time.time()\n        print(f\"{func.__name__} 執行時間: {end - start:.4f} 秒\")\n        return result\n    return wrapper\n\n# CPU 密集型任務：計算 Fibonacci 數列\ndef fib(n):\n    if n \u003C= 1:\n        return n\n    return fib(n - 1) + fib(n - 2)\n\n# I/O 綁定任務：模擬網路請求（全局函數）\ndef sync_io_task():\n    time.sleep(1)  # 模擬 1 秒的 I/O 延遲\n\n# 異步 I/O 任務\nasync def io_bound_task():\n    await asyncio.sleep(1)  # 模擬 1 秒的 I/O 延遲\n    return \"I/O 任務完成\"\n\n# 多線程實現\n@timing_decorator\ndef run_multithreading(n_tasks, task_type=\"cpu\"):\n    threads = []\n    if task_type == \"cpu\":\n        for _ in range(n_tasks):\n            t = threading.Thread(target=fib, args=(35,))\n            threads.append(t)\n            t.start()\n        for t in threads:\n            t.join()\n    else:  # I/O 任務\n        for _ in range(n_tasks):\n            t = threading.Thread(target=sync_io_task)\n            threads.append(t)\n            t.start()\n        for t in threads:\n            t.join()\n\n# 多進程實現\n@timing_decorator\ndef run_multiprocessing(n_tasks, task_type=\"cpu\"):\n    processes = []\n    if task_type == \"cpu\":\n        for _ in range(n_tasks):\n            p = multiprocessing.Process(target=fib, args=(35,))\n            processes.append(p)\n            p.start()\n        for p in processes:\n            p.join()\n    else:  # I/O 任務\n        for _ in range(n_tasks):\n            p = multiprocessing.Process(target=sync_io_task)\n            processes.append(p)\n            p.start()\n        for p in processes:\n            p.join()\n\n# Asyncio 實現\n@timing_decorator\nasync def run_asyncio(n_tasks):\n    tasks = [io_bound_task() for _ in range(n_tasks)]\n    await asyncio.gather(*tasks)\n\n# 禁用 GIL 的多線程實現（需 Python 3.13 --disable-gil）\n@timing_decorator\ndef run_nogil_multithreading(n_tasks, task_type=\"cpu\"):\n    with ThreadPoolExecutor(max_workers=n_tasks) as executor:\n        if task_type == \"cpu\":\n            futures = [executor.submit(fib, 35) for _ in range(n_tasks)]\n        else:  # I/O 任務\n            futures = [executor.submit(sync_io_task) for _ in range(n_tasks)]\n        for future in futures:\n            future.result()\n\n# 主程式\nif __name__ == \"__main__\":\n    n_tasks = 4  # 任務數量\n\n    print(\"=== CPU 密集型任務 (計算 Fibonacci 數列) ===\")\n    print(\"多線程 (Multithreading):\")\n    run_multithreading(n_tasks, task_type=\"cpu\")\n\n    print(\"\\n多進程 (Multiprocessing):\")\n    run_multiprocessing(n_tasks, task_type=\"cpu\")\n\n    if sys.version_info >= (3, 13) and hasattr(sys, \"disable_gil\"):\n        print(\"\\n禁用 GIL 的多線程:\")\n        run_nogil_multithreading(n_tasks, task_type=\"cpu\")\n    else:\n        print(\"\\n禁用 GIL 的多線程: 需要 Python 3.13 並啟用 --disable-gil\")\n\n    print(\"\\n=== I/O 綁定任務 (模擬網路請求) ===\")\n    print(\"多線程 (Multithreading):\")\n    run_multithreading(n_tasks, task_type=\"io\")\n\n    print(\"\\n多進程 (Multiprocessing):\")\n    run_multiprocessing(n_tasks, task_type=\"io\")\n\n    print(\"\\nAsyncio:\")\n    asyncio.run(run_asyncio(n_tasks))\n\n    if sys.version_info >= (3, 13) and hasattr(sys, \"disable_gil\"):\n        print(\"\\n禁用 GIL 的多線程:\")\n        run_nogil_multithreading(n_tasks, task_type=\"io\")\n    else:\n        print(\"\\n禁用 GIL 的多線程: 需要 Python 3.13 並啟用 --disable-gil\")\n",[35,3855,3856,3863,3870,3877,3884,3891,3903,3915,3919,3924,3935,3943,3963,3973,3991,4000,4046,4052,4060,4064,4069,4078,4090,4096,4120,4124,4129,4139,4152,4156,4161,4174,4188,4195,4199,4204,4209,4226,4235,4249,4262,4294,4299,4304,4316,4321,4332,4344,4359,4363,4367,4377,4381,4385,4390,4394,4409,4419,4432,4445,4472,4478,4484,4497,4503,4512,4525,4540,4545,4550,4561,4566,4571,4577,4582,4594,4616,4629,4634,4640,4645,4661,4684,4697,4722,4732,4752,4765,4771,4776,4782,4799,4813,4818,4831,4843,4858,4863,4880,4894,4899,4934,4950,4964,4971,4987,4992,5008,5019,5033,5038,5053,5066,5071,5087,5093,5098,5127,5142,5155,5162],{"__ignoreMap":33},[38,3857,3858,3860],{"class":40,"line":41},[38,3859,556],{"class":57},[38,3861,3862],{"class":65}," time\n",[38,3864,3865,3867],{"class":40,"line":48},[38,3866,556],{"class":57},[38,3868,3869],{"class":65}," threading\n",[38,3871,3872,3874],{"class":40,"line":54},[38,3873,556],{"class":57},[38,3875,3876],{"class":65}," multiprocessing\n",[38,3878,3879,3881],{"class":40,"line":69},[38,3880,556],{"class":57},[38,3882,3883],{"class":65}," asyncio\n",[38,3885,3886,3888],{"class":40,"line":108},[38,3887,556],{"class":57},[38,3889,3890],{"class":65}," sys\n",[38,3892,3893,3895,3898,3900],{"class":40,"line":126},[38,3894,550],{"class":57},[38,3896,3897],{"class":65}," concurrent.futures ",[38,3899,556],{"class":57},[38,3901,3902],{"class":65}," ThreadPoolExecutor\n",[38,3904,3905,3907,3910,3912],{"class":40,"line":132},[38,3906,550],{"class":57},[38,3908,3909],{"class":65}," functools ",[38,3911,556],{"class":57},[38,3913,3914],{"class":65}," wraps\n",[38,3916,3917],{"class":40,"line":148},[38,3918,181],{"emptyLinePlaceholder":180},[38,3920,3921],{"class":40,"line":177},[38,3922,3923],{"class":44},"# 計時裝飾器，用於測量執行時間\n",[38,3925,3926,3929,3932],{"class":40,"line":184},[38,3927,3928],{"class":57},"def",[38,3930,3931],{"class":61}," timing_decorator",[38,3933,3934],{"class":65},"(func):\n",[38,3936,3937,3940],{"class":40,"line":190},[38,3938,3939],{"class":61},"    @wraps",[38,3941,3942],{"class":65},"(func)\n",[38,3944,3945,3947,3950,3952,3954,3957,3960],{"class":40,"line":204},[38,3946,72],{"class":57},[38,3948,3949],{"class":61}," wrapper",[38,3951,608],{"class":65},[38,3953,403],{"class":57},[38,3955,3956],{"class":65},"args, ",[38,3958,3959],{"class":57},"**",[38,3961,3962],{"class":65},"kwargs):\n",[38,3964,3965,3968,3970],{"class":40,"line":210},[38,3966,3967],{"class":65},"        start ",[38,3969,154],{"class":57},[38,3971,3972],{"class":65}," time.time()\n",[38,3974,3975,3977,3979,3982,3984,3986,3988],{"class":40,"line":224},[38,3976,390],{"class":65},[38,3978,154],{"class":57},[38,3980,3981],{"class":65}," func(",[38,3983,403],{"class":57},[38,3985,3956],{"class":65},[38,3987,3959],{"class":57},[38,3989,3990],{"class":65},"kwargs)\n",[38,3992,3993,3996,3998],{"class":40,"line":241},[38,3994,3995],{"class":65},"        end ",[38,3997,154],{"class":57},[38,3999,3972],{"class":65},[38,4001,4002,4005,4007,4010,4013,4016,4019,4022,4025,4027,4030,4032,4035,4038,4041,4044],{"class":40,"line":255},[38,4003,4004],{"class":81},"        print",[38,4006,608],{"class":65},[38,4008,4009],{"class":57},"f",[38,4011,4012],{"class":1620},"\"",[38,4014,4015],{"class":81},"{",[38,4017,4018],{"class":65},"func.",[38,4020,4021],{"class":81},"__name__}",[38,4023,4024],{"class":1620}," 執行時間: ",[38,4026,4015],{"class":81},[38,4028,4029],{"class":65},"end ",[38,4031,269],{"class":57},[38,4033,4034],{"class":65}," start",[38,4036,4037],{"class":57},":.4f",[38,4039,4040],{"class":81},"}",[38,4042,4043],{"class":1620}," 秒\"",[38,4045,1457],{"class":65},[38,4047,4048,4050],{"class":40,"line":277},[38,4049,325],{"class":57},[38,4051,498],{"class":65},[38,4053,4054,4057],{"class":40,"line":294},[38,4055,4056],{"class":57},"    return",[38,4058,4059],{"class":65}," wrapper\n",[38,4061,4062],{"class":40,"line":302},[38,4063,181],{"emptyLinePlaceholder":180},[38,4065,4066],{"class":40,"line":312},[38,4067,4068],{"class":44},"# CPU 密集型任務：計算 Fibonacci 數列\n",[38,4070,4071,4073,4076],{"class":40,"line":317},[38,4072,3928],{"class":57},[38,4074,4075],{"class":61}," fib",[38,4077,123],{"class":65},[38,4079,4080,4082,4084,4086,4088],{"class":40,"line":322},[38,4081,717],{"class":57},[38,4083,266],{"class":65},[38,4085,1127],{"class":57},[38,4087,272],{"class":81},[38,4089,66],{"class":65},[38,4091,4092,4094],{"class":40,"line":798},[38,4093,325],{"class":57},[38,4095,462],{"class":65},[38,4097,4098,4100,4103,4105,4107,4109,4111,4113,4115,4118],{"class":40,"line":807},[38,4099,4056],{"class":57},[38,4101,4102],{"class":65}," fib(n ",[38,4104,269],{"class":57},[38,4106,272],{"class":81},[38,4108,2885],{"class":65},[38,4110,166],{"class":57},[38,4112,4102],{"class":65},[38,4114,269],{"class":57},[38,4116,4117],{"class":81}," 2",[38,4119,1457],{"class":65},[38,4121,4122],{"class":40,"line":827},[38,4123,181],{"emptyLinePlaceholder":180},[38,4125,4126],{"class":40,"line":838},[38,4127,4128],{"class":44},"# I/O 綁定任務：模擬網路請求（全局函數）\n",[38,4130,4131,4133,4136],{"class":40,"line":851},[38,4132,3928],{"class":57},[38,4134,4135],{"class":61}," sync_io_task",[38,4137,4138],{"class":65},"():\n",[38,4140,4141,4144,4146,4149],{"class":40,"line":868},[38,4142,4143],{"class":65},"    time.sleep(",[38,4145,160],{"class":81},[38,4147,4148],{"class":65},")  ",[38,4150,4151],{"class":44},"# 模擬 1 秒的 I/O 延遲\n",[38,4153,4154],{"class":40,"line":879},[38,4155,181],{"emptyLinePlaceholder":180},[38,4157,4158],{"class":40,"line":897},[38,4159,4160],{"class":44},"# 異步 I/O 任務\n",[38,4162,4163,4166,4169,4172],{"class":40,"line":915},[38,4164,4165],{"class":57},"async",[38,4167,4168],{"class":57}," def",[38,4170,4171],{"class":61}," io_bound_task",[38,4173,4138],{"class":65},[38,4175,4176,4179,4182,4184,4186],{"class":40,"line":929},[38,4177,4178],{"class":57},"    await",[38,4180,4181],{"class":65}," asyncio.sleep(",[38,4183,160],{"class":81},[38,4185,4148],{"class":65},[38,4187,4151],{"class":44},[38,4189,4190,4192],{"class":40,"line":943},[38,4191,4056],{"class":57},[38,4193,4194],{"class":1620}," \"I/O 任務完成\"\n",[38,4196,4197],{"class":40,"line":962},[38,4198,181],{"emptyLinePlaceholder":180},[38,4200,4201],{"class":40,"line":968},[38,4202,4203],{"class":44},"# 多線程實現\n",[38,4205,4206],{"class":40,"line":986},[38,4207,4208],{"class":61},"@timing_decorator\n",[38,4210,4211,4213,4216,4219,4221,4224],{"class":40,"line":3294},[38,4212,3928],{"class":57},[38,4214,4215],{"class":61}," run_multithreading",[38,4217,4218],{"class":65},"(n_tasks, task_type",[38,4220,154],{"class":57},[38,4222,4223],{"class":1620},"\"cpu\"",[38,4225,619],{"class":65},[38,4227,4228,4231,4233],{"class":40,"line":3304},[38,4229,4230],{"class":65},"    threads ",[38,4232,154],{"class":57},[38,4234,2452],{"class":65},[38,4236,4237,4239,4242,4244,4247],{"class":40,"line":3314},[38,4238,717],{"class":57},[38,4240,4241],{"class":65}," task_type ",[38,4243,1349],{"class":57},[38,4245,4246],{"class":1620}," \"cpu\"",[38,4248,66],{"class":65},[38,4250,4251,4253,4255,4257,4259],{"class":40,"line":3326},[38,4252,111],{"class":57},[38,4254,138],{"class":65},[38,4256,117],{"class":57},[38,4258,120],{"class":81},[38,4260,4261],{"class":65},"(n_tasks):\n",[38,4263,4264,4267,4269,4272,4276,4278,4281,4284,4286,4288,4291],{"class":40,"line":3336},[38,4265,4266],{"class":65},"            t ",[38,4268,154],{"class":57},[38,4270,4271],{"class":65}," threading.Thread(",[38,4273,4275],{"class":4274},"s4XuR","target",[38,4277,154],{"class":57},[38,4279,4280],{"class":65},"fib, ",[38,4282,4283],{"class":4274},"args",[38,4285,154],{"class":57},[38,4287,608],{"class":65},[38,4289,4290],{"class":81},"35",[38,4292,4293],{"class":65},",))\n",[38,4295,4296],{"class":40,"line":3353},[38,4297,4298],{"class":65},"            threads.append(t)\n",[38,4300,4301],{"class":40,"line":3364},[38,4302,4303],{"class":65},"            t.start()\n",[38,4305,4306,4308,4311,4313],{"class":40,"line":3373},[38,4307,111],{"class":57},[38,4309,4310],{"class":65}," t ",[38,4312,117],{"class":57},[38,4314,4315],{"class":65}," threads:\n",[38,4317,4318],{"class":40,"line":3389},[38,4319,4320],{"class":65},"            t.join()\n",[38,4322,4323,4326,4329],{"class":40,"line":3400},[38,4324,4325],{"class":57},"    else",[38,4327,4328],{"class":65},":  ",[38,4330,4331],{"class":44},"# I/O 任務\n",[38,4333,4334,4336,4338,4340,4342],{"class":40,"line":3409},[38,4335,111],{"class":57},[38,4337,138],{"class":65},[38,4339,117],{"class":57},[38,4341,120],{"class":81},[38,4343,4261],{"class":65},[38,4345,4346,4348,4350,4352,4354,4356],{"class":40,"line":3414},[38,4347,4266],{"class":65},[38,4349,154],{"class":57},[38,4351,4271],{"class":65},[38,4353,4275],{"class":4274},[38,4355,154],{"class":57},[38,4357,4358],{"class":65},"sync_io_task)\n",[38,4360,4361],{"class":40,"line":3433},[38,4362,4298],{"class":65},[38,4364,4365],{"class":40,"line":3438},[38,4366,4303],{"class":65},[38,4368,4369,4371,4373,4375],{"class":40,"line":3457},[38,4370,111],{"class":57},[38,4372,4310],{"class":65},[38,4374,117],{"class":57},[38,4376,4315],{"class":65},[38,4378,4379],{"class":40,"line":3472},[38,4380,4320],{"class":65},[38,4382,4383],{"class":40,"line":3483},[38,4384,181],{"emptyLinePlaceholder":180},[38,4386,4387],{"class":40,"line":3489},[38,4388,4389],{"class":44},"# 多進程實現\n",[38,4391,4392],{"class":40,"line":3498},[38,4393,4208],{"class":61},[38,4395,4396,4398,4401,4403,4405,4407],{"class":40,"line":3504},[38,4397,3928],{"class":57},[38,4399,4400],{"class":61}," run_multiprocessing",[38,4402,4218],{"class":65},[38,4404,154],{"class":57},[38,4406,4223],{"class":1620},[38,4408,619],{"class":65},[38,4410,4412,4415,4417],{"class":40,"line":4411},57,[38,4413,4414],{"class":65},"    processes ",[38,4416,154],{"class":57},[38,4418,2452],{"class":65},[38,4420,4422,4424,4426,4428,4430],{"class":40,"line":4421},58,[38,4423,717],{"class":57},[38,4425,4241],{"class":65},[38,4427,1349],{"class":57},[38,4429,4246],{"class":1620},[38,4431,66],{"class":65},[38,4433,4435,4437,4439,4441,4443],{"class":40,"line":4434},59,[38,4436,111],{"class":57},[38,4438,138],{"class":65},[38,4440,117],{"class":57},[38,4442,120],{"class":81},[38,4444,4261],{"class":65},[38,4446,4448,4451,4453,4456,4458,4460,4462,4464,4466,4468,4470],{"class":40,"line":4447},60,[38,4449,4450],{"class":65},"            p ",[38,4452,154],{"class":57},[38,4454,4455],{"class":65}," multiprocessing.Process(",[38,4457,4275],{"class":4274},[38,4459,154],{"class":57},[38,4461,4280],{"class":65},[38,4463,4283],{"class":4274},[38,4465,154],{"class":57},[38,4467,608],{"class":65},[38,4469,4290],{"class":81},[38,4471,4293],{"class":65},[38,4473,4475],{"class":40,"line":4474},61,[38,4476,4477],{"class":65},"            processes.append(p)\n",[38,4479,4481],{"class":40,"line":4480},62,[38,4482,4483],{"class":65},"            p.start()\n",[38,4485,4487,4489,4492,4494],{"class":40,"line":4486},63,[38,4488,111],{"class":57},[38,4490,4491],{"class":65}," p ",[38,4493,117],{"class":57},[38,4495,4496],{"class":65}," processes:\n",[38,4498,4500],{"class":40,"line":4499},64,[38,4501,4502],{"class":65},"            p.join()\n",[38,4504,4506,4508,4510],{"class":40,"line":4505},65,[38,4507,4325],{"class":57},[38,4509,4328],{"class":65},[38,4511,4331],{"class":44},[38,4513,4515,4517,4519,4521,4523],{"class":40,"line":4514},66,[38,4516,111],{"class":57},[38,4518,138],{"class":65},[38,4520,117],{"class":57},[38,4522,120],{"class":81},[38,4524,4261],{"class":65},[38,4526,4528,4530,4532,4534,4536,4538],{"class":40,"line":4527},67,[38,4529,4450],{"class":65},[38,4531,154],{"class":57},[38,4533,4455],{"class":65},[38,4535,4275],{"class":4274},[38,4537,154],{"class":57},[38,4539,4358],{"class":65},[38,4541,4543],{"class":40,"line":4542},68,[38,4544,4477],{"class":65},[38,4546,4548],{"class":40,"line":4547},69,[38,4549,4483],{"class":65},[38,4551,4553,4555,4557,4559],{"class":40,"line":4552},70,[38,4554,111],{"class":57},[38,4556,4491],{"class":65},[38,4558,117],{"class":57},[38,4560,4496],{"class":65},[38,4562,4564],{"class":40,"line":4563},71,[38,4565,4502],{"class":65},[38,4567,4569],{"class":40,"line":4568},72,[38,4570,181],{"emptyLinePlaceholder":180},[38,4572,4574],{"class":40,"line":4573},73,[38,4575,4576],{"class":44},"# Asyncio 實現\n",[38,4578,4580],{"class":40,"line":4579},74,[38,4581,4208],{"class":61},[38,4583,4585,4587,4589,4592],{"class":40,"line":4584},75,[38,4586,4165],{"class":57},[38,4588,4168],{"class":57},[38,4590,4591],{"class":61}," run_asyncio",[38,4593,4261],{"class":65},[38,4595,4597,4600,4602,4605,4607,4609,4611,4613],{"class":40,"line":4596},76,[38,4598,4599],{"class":65},"    tasks ",[38,4601,154],{"class":57},[38,4603,4604],{"class":65}," [io_bound_task() ",[38,4606,408],{"class":57},[38,4608,138],{"class":65},[38,4610,117],{"class":57},[38,4612,120],{"class":81},[38,4614,4615],{"class":65},"(n_tasks)]\n",[38,4617,4619,4621,4624,4626],{"class":40,"line":4618},77,[38,4620,4178],{"class":57},[38,4622,4623],{"class":65}," asyncio.gather(",[38,4625,403],{"class":57},[38,4627,4628],{"class":65},"tasks)\n",[38,4630,4632],{"class":40,"line":4631},78,[38,4633,181],{"emptyLinePlaceholder":180},[38,4635,4637],{"class":40,"line":4636},79,[38,4638,4639],{"class":44},"# 禁用 GIL 的多線程實現（需 Python 3.13 --disable-gil）\n",[38,4641,4643],{"class":40,"line":4642},80,[38,4644,4208],{"class":61},[38,4646,4648,4650,4653,4655,4657,4659],{"class":40,"line":4647},81,[38,4649,3928],{"class":57},[38,4651,4652],{"class":61}," run_nogil_multithreading",[38,4654,4218],{"class":65},[38,4656,154],{"class":57},[38,4658,4223],{"class":1620},[38,4660,619],{"class":65},[38,4662,4664,4667,4670,4673,4675,4678,4681],{"class":40,"line":4663},82,[38,4665,4666],{"class":57},"    with",[38,4668,4669],{"class":65}," ThreadPoolExecutor(",[38,4671,4672],{"class":4274},"max_workers",[38,4674,154],{"class":57},[38,4676,4677],{"class":65},"n_tasks) ",[38,4679,4680],{"class":57},"as",[38,4682,4683],{"class":65}," executor:\n",[38,4685,4687,4689,4691,4693,4695],{"class":40,"line":4686},83,[38,4688,2894],{"class":57},[38,4690,4241],{"class":65},[38,4692,1349],{"class":57},[38,4694,4246],{"class":1620},[38,4696,66],{"class":65},[38,4698,4700,4703,4705,4708,4710,4712,4714,4716,4718,4720],{"class":40,"line":4699},84,[38,4701,4702],{"class":65},"            futures ",[38,4704,154],{"class":57},[38,4706,4707],{"class":65}," [executor.submit(fib, ",[38,4709,4290],{"class":81},[38,4711,2885],{"class":65},[38,4713,408],{"class":57},[38,4715,138],{"class":65},[38,4717,117],{"class":57},[38,4719,120],{"class":81},[38,4721,4615],{"class":65},[38,4723,4725,4728,4730],{"class":40,"line":4724},85,[38,4726,4727],{"class":57},"        else",[38,4729,4328],{"class":65},[38,4731,4331],{"class":44},[38,4733,4735,4737,4739,4742,4744,4746,4748,4750],{"class":40,"line":4734},86,[38,4736,4702],{"class":65},[38,4738,154],{"class":57},[38,4740,4741],{"class":65}," [executor.submit(sync_io_task) ",[38,4743,408],{"class":57},[38,4745,138],{"class":65},[38,4747,117],{"class":57},[38,4749,120],{"class":81},[38,4751,4615],{"class":65},[38,4753,4755,4757,4760,4762],{"class":40,"line":4754},87,[38,4756,111],{"class":57},[38,4758,4759],{"class":65}," future ",[38,4761,117],{"class":57},[38,4763,4764],{"class":65}," futures:\n",[38,4766,4768],{"class":40,"line":4767},88,[38,4769,4770],{"class":65},"            future.result()\n",[38,4772,4774],{"class":40,"line":4773},89,[38,4775,181],{"emptyLinePlaceholder":180},[38,4777,4779],{"class":40,"line":4778},90,[38,4780,4781],{"class":44},"# 主程式\n",[38,4783,4785,4788,4791,4794,4797],{"class":40,"line":4784},91,[38,4786,4787],{"class":57},"if",[38,4789,4790],{"class":81}," __name__",[38,4792,4793],{"class":57}," ==",[38,4795,4796],{"class":1620}," \"__main__\"",[38,4798,66],{"class":65},[38,4800,4802,4805,4807,4810],{"class":40,"line":4801},92,[38,4803,4804],{"class":65},"    n_tasks ",[38,4806,154],{"class":57},[38,4808,4809],{"class":81}," 4",[38,4811,4812],{"class":44},"  # 任務數量\n",[38,4814,4816],{"class":40,"line":4815},93,[38,4817,181],{"emptyLinePlaceholder":180},[38,4819,4821,4824,4826,4829],{"class":40,"line":4820},94,[38,4822,4823],{"class":81},"    print",[38,4825,608],{"class":65},[38,4827,4828],{"class":1620},"\"=== CPU 密集型任務 (計算 Fibonacci 數列) ===\"",[38,4830,1457],{"class":65},[38,4832,4834,4836,4838,4841],{"class":40,"line":4833},95,[38,4835,4823],{"class":81},[38,4837,608],{"class":65},[38,4839,4840],{"class":1620},"\"多線程 (Multithreading):\"",[38,4842,1457],{"class":65},[38,4844,4846,4849,4852,4854,4856],{"class":40,"line":4845},96,[38,4847,4848],{"class":65},"    run_multithreading(n_tasks, ",[38,4850,4851],{"class":4274},"task_type",[38,4853,154],{"class":57},[38,4855,4223],{"class":1620},[38,4857,1457],{"class":65},[38,4859,4861],{"class":40,"line":4860},97,[38,4862,181],{"emptyLinePlaceholder":180},[38,4864,4866,4868,4870,4872,4875,4878],{"class":40,"line":4865},98,[38,4867,4823],{"class":81},[38,4869,608],{"class":65},[38,4871,4012],{"class":1620},[38,4873,4874],{"class":81},"\\n",[38,4876,4877],{"class":1620},"多進程 (Multiprocessing):\"",[38,4879,1457],{"class":65},[38,4881,4883,4886,4888,4890,4892],{"class":40,"line":4882},99,[38,4884,4885],{"class":65},"    run_multiprocessing(n_tasks, ",[38,4887,4851],{"class":4274},[38,4889,154],{"class":57},[38,4891,4223],{"class":1620},[38,4893,1457],{"class":65},[38,4895,4897],{"class":40,"line":4896},100,[38,4898,181],{"emptyLinePlaceholder":180},[38,4900,4902,4904,4907,4909,4911,4914,4916,4919,4921,4923,4926,4929,4932],{"class":40,"line":4901},101,[38,4903,717],{"class":57},[38,4905,4906],{"class":65}," sys.version_info ",[38,4908,888],{"class":57},[38,4910,2502],{"class":65},[38,4912,4913],{"class":81},"3",[38,4915,613],{"class":65},[38,4917,4918],{"class":81},"13",[38,4920,2885],{"class":65},[38,4922,1282],{"class":57},[38,4924,4925],{"class":81}," hasattr",[38,4927,4928],{"class":65},"(sys, ",[38,4930,4931],{"class":1620},"\"disable_gil\"",[38,4933,619],{"class":65},[38,4935,4937,4939,4941,4943,4945,4948],{"class":40,"line":4936},102,[38,4938,4004],{"class":81},[38,4940,608],{"class":65},[38,4942,4012],{"class":1620},[38,4944,4874],{"class":81},[38,4946,4947],{"class":1620},"禁用 GIL 的多線程:\"",[38,4949,1457],{"class":65},[38,4951,4953,4956,4958,4960,4962],{"class":40,"line":4952},103,[38,4954,4955],{"class":65},"        run_nogil_multithreading(n_tasks, ",[38,4957,4851],{"class":4274},[38,4959,154],{"class":57},[38,4961,4223],{"class":1620},[38,4963,1457],{"class":65},[38,4965,4967,4969],{"class":40,"line":4966},104,[38,4968,4325],{"class":57},[38,4970,66],{"class":65},[38,4972,4974,4976,4978,4980,4982,4985],{"class":40,"line":4973},105,[38,4975,4004],{"class":81},[38,4977,608],{"class":65},[38,4979,4012],{"class":1620},[38,4981,4874],{"class":81},[38,4983,4984],{"class":1620},"禁用 GIL 的多線程: 需要 Python 3.13 並啟用 --disable-gil\"",[38,4986,1457],{"class":65},[38,4988,4990],{"class":40,"line":4989},106,[38,4991,181],{"emptyLinePlaceholder":180},[38,4993,4995,4997,4999,5001,5003,5006],{"class":40,"line":4994},107,[38,4996,4823],{"class":81},[38,4998,608],{"class":65},[38,5000,4012],{"class":1620},[38,5002,4874],{"class":81},[38,5004,5005],{"class":1620},"=== I/O 綁定任務 (模擬網路請求) ===\"",[38,5007,1457],{"class":65},[38,5009,5011,5013,5015,5017],{"class":40,"line":5010},108,[38,5012,4823],{"class":81},[38,5014,608],{"class":65},[38,5016,4840],{"class":1620},[38,5018,1457],{"class":65},[38,5020,5022,5024,5026,5028,5031],{"class":40,"line":5021},109,[38,5023,4848],{"class":65},[38,5025,4851],{"class":4274},[38,5027,154],{"class":57},[38,5029,5030],{"class":1620},"\"io\"",[38,5032,1457],{"class":65},[38,5034,5036],{"class":40,"line":5035},110,[38,5037,181],{"emptyLinePlaceholder":180},[38,5039,5041,5043,5045,5047,5049,5051],{"class":40,"line":5040},111,[38,5042,4823],{"class":81},[38,5044,608],{"class":65},[38,5046,4012],{"class":1620},[38,5048,4874],{"class":81},[38,5050,4877],{"class":1620},[38,5052,1457],{"class":65},[38,5054,5056,5058,5060,5062,5064],{"class":40,"line":5055},112,[38,5057,4885],{"class":65},[38,5059,4851],{"class":4274},[38,5061,154],{"class":57},[38,5063,5030],{"class":1620},[38,5065,1457],{"class":65},[38,5067,5069],{"class":40,"line":5068},113,[38,5070,181],{"emptyLinePlaceholder":180},[38,5072,5074,5076,5078,5080,5082,5085],{"class":40,"line":5073},114,[38,5075,4823],{"class":81},[38,5077,608],{"class":65},[38,5079,4012],{"class":1620},[38,5081,4874],{"class":81},[38,5083,5084],{"class":1620},"Asyncio:\"",[38,5086,1457],{"class":65},[38,5088,5090],{"class":40,"line":5089},115,[38,5091,5092],{"class":65},"    asyncio.run(run_asyncio(n_tasks))\n",[38,5094,5096],{"class":40,"line":5095},116,[38,5097,181],{"emptyLinePlaceholder":180},[38,5099,5101,5103,5105,5107,5109,5111,5113,5115,5117,5119,5121,5123,5125],{"class":40,"line":5100},117,[38,5102,717],{"class":57},[38,5104,4906],{"class":65},[38,5106,888],{"class":57},[38,5108,2502],{"class":65},[38,5110,4913],{"class":81},[38,5112,613],{"class":65},[38,5114,4918],{"class":81},[38,5116,2885],{"class":65},[38,5118,1282],{"class":57},[38,5120,4925],{"class":81},[38,5122,4928],{"class":65},[38,5124,4931],{"class":1620},[38,5126,619],{"class":65},[38,5128,5130,5132,5134,5136,5138,5140],{"class":40,"line":5129},118,[38,5131,4004],{"class":81},[38,5133,608],{"class":65},[38,5135,4012],{"class":1620},[38,5137,4874],{"class":81},[38,5139,4947],{"class":1620},[38,5141,1457],{"class":65},[38,5143,5145,5147,5149,5151,5153],{"class":40,"line":5144},119,[38,5146,4955],{"class":65},[38,5148,4851],{"class":4274},[38,5150,154],{"class":57},[38,5152,5030],{"class":1620},[38,5154,1457],{"class":65},[38,5156,5158,5160],{"class":40,"line":5157},120,[38,5159,4325],{"class":57},[38,5161,66],{"class":65},[38,5163,5165,5167,5169,5171,5173,5175],{"class":40,"line":5164},121,[38,5166,4004],{"class":81},[38,5168,608],{"class":65},[38,5170,4012],{"class":1620},[38,5172,4874],{"class":81},[38,5174,4984],{"class":1620},[38,5176,1457],{"class":65},[3533,5178,5179],{"id":5179},"執行結果分析",[28,5181,5185],{"className":5182,"code":5183,"language":5184,"meta":33,"style":33},"language-bash shiki shiki-themes github-light github-dark","$ uv run --no-project --python 3.13.5+freethreaded test.py\n\n=== CPU 密集型任務 (計算 Fibonacci 數列) ===\n多線程 (Multithreading):\nrun_multithreading 執行時間: 0.8912 秒\n\n多進程 (Multiprocessing):\nrun_multiprocessing 執行時間: 1.0846 秒\n\n禁用 GIL 的多線程:\nGIL 狀態: 禁用\nrun_nogil_multithreading 執行時間: 0.8713 秒\n\n=== I/O 綁定任務 (模擬網路請求) ===\n多線程 (Multithreading):\nrun_multithreading 執行時間: 1.0072 秒\n\n多進程 (Multiprocessing):\nrun_multiprocessing 執行時間: 1.1046 秒\n\nAsyncio:\nrun_asyncio 執行時間: 0.0000 秒\n\n禁用 GIL 的多線程:\nGIL 狀態: 禁用\nrun_nogil_multithreading 執行時間: 1.0093 秒\n","bash",[35,5186,5187,5210,5214,5237,5245,5259,5263,5271,5283,5287,5298,5309,5321,5325,5338,5344,5355,5359,5365,5376,5380,5385,5397,5401,5409,5417],{"__ignoreMap":33},[38,5188,5189,5192,5195,5198,5201,5204,5207],{"class":40,"line":41},[38,5190,5191],{"class":61},"$",[38,5193,5194],{"class":1620}," uv",[38,5196,5197],{"class":1620}," run",[38,5199,5200],{"class":81}," --no-project",[38,5202,5203],{"class":81}," --python",[38,5205,5206],{"class":1620}," 3.13.5+freethreaded",[38,5208,5209],{"class":1620}," test.py\n",[38,5211,5212],{"class":40,"line":48},[38,5213,181],{"emptyLinePlaceholder":180},[38,5215,5216,5219,5222,5225,5228,5231,5234],{"class":40,"line":54},[38,5217,5218],{"class":1620},"===",[38,5220,5221],{"class":1620}," CPU",[38,5223,5224],{"class":1620}," 密集型任務",[38,5226,5227],{"class":65}," (計算 ",[38,5229,5230],{"class":1620},"Fibonacci",[38,5232,5233],{"class":1620}," 數列",[38,5235,5236],{"class":65},") ===\n",[38,5238,5239,5242],{"class":40,"line":69},[38,5240,5241],{"class":61},"多線程",[38,5243,5244],{"class":65}," (Multithreading):\n",[38,5246,5247,5250,5253,5256],{"class":40,"line":108},[38,5248,5249],{"class":61},"run_multithreading",[38,5251,5252],{"class":1620}," 執行時間:",[38,5254,5255],{"class":81}," 0.8912",[38,5257,5258],{"class":1620}," 秒\n",[38,5260,5261],{"class":40,"line":126},[38,5262,181],{"emptyLinePlaceholder":180},[38,5264,5265,5268],{"class":40,"line":132},[38,5266,5267],{"class":61},"多進程",[38,5269,5270],{"class":65}," (Multiprocessing):\n",[38,5272,5273,5276,5278,5281],{"class":40,"line":148},[38,5274,5275],{"class":61},"run_multiprocessing",[38,5277,5252],{"class":1620},[38,5279,5280],{"class":81}," 1.0846",[38,5282,5258],{"class":1620},[38,5284,5285],{"class":40,"line":177},[38,5286,181],{"emptyLinePlaceholder":180},[38,5288,5289,5292,5295],{"class":40,"line":184},[38,5290,5291],{"class":61},"禁用",[38,5293,5294],{"class":1620}," GIL",[38,5296,5297],{"class":1620}," 的多線程:\n",[38,5299,5300,5303,5306],{"class":40,"line":190},[38,5301,5302],{"class":61},"GIL",[38,5304,5305],{"class":1620}," 狀態:",[38,5307,5308],{"class":1620}," 禁用\n",[38,5310,5311,5314,5316,5319],{"class":40,"line":204},[38,5312,5313],{"class":61},"run_nogil_multithreading",[38,5315,5252],{"class":1620},[38,5317,5318],{"class":81}," 0.8713",[38,5320,5258],{"class":1620},[38,5322,5323],{"class":40,"line":210},[38,5324,181],{"emptyLinePlaceholder":180},[38,5326,5327,5329,5332,5335],{"class":40,"line":224},[38,5328,5218],{"class":1620},[38,5330,5331],{"class":1620}," I/O",[38,5333,5334],{"class":1620}," 綁定任務",[38,5336,5337],{"class":65}," (模擬網路請求) ===\n",[38,5339,5340,5342],{"class":40,"line":241},[38,5341,5241],{"class":61},[38,5343,5244],{"class":65},[38,5345,5346,5348,5350,5353],{"class":40,"line":255},[38,5347,5249],{"class":61},[38,5349,5252],{"class":1620},[38,5351,5352],{"class":81}," 1.0072",[38,5354,5258],{"class":1620},[38,5356,5357],{"class":40,"line":277},[38,5358,181],{"emptyLinePlaceholder":180},[38,5360,5361,5363],{"class":40,"line":294},[38,5362,5267],{"class":61},[38,5364,5270],{"class":65},[38,5366,5367,5369,5371,5374],{"class":40,"line":302},[38,5368,5275],{"class":61},[38,5370,5252],{"class":1620},[38,5372,5373],{"class":81}," 1.1046",[38,5375,5258],{"class":1620},[38,5377,5378],{"class":40,"line":312},[38,5379,181],{"emptyLinePlaceholder":180},[38,5381,5382],{"class":40,"line":317},[38,5383,5384],{"class":61},"Asyncio:\n",[38,5386,5387,5390,5392,5395],{"class":40,"line":322},[38,5388,5389],{"class":61},"run_asyncio",[38,5391,5252],{"class":1620},[38,5393,5394],{"class":81}," 0.0000",[38,5396,5258],{"class":1620},[38,5398,5399],{"class":40,"line":798},[38,5400,181],{"emptyLinePlaceholder":180},[38,5402,5403,5405,5407],{"class":40,"line":807},[38,5404,5291],{"class":61},[38,5406,5294],{"class":1620},[38,5408,5297],{"class":1620},[38,5410,5411,5413,5415],{"class":40,"line":827},[38,5412,5302],{"class":61},[38,5414,5305],{"class":1620},[38,5416,5308],{"class":1620},[38,5418,5419,5421,5423,5426],{"class":40,"line":838},[38,5420,5313],{"class":61},[38,5422,5252],{"class":1620},[38,5424,5425],{"class":81}," 1.0093",[38,5427,5258],{"class":1620},[3547,5429,5431],{"id":5430},"cpu-密集型任務計算-fibonacci-數列","CPU 密集型任務（計算 Fibonacci 數列）",[11,5433,5434,5435],{},"執行時間排序：",[3556,5436,5437],{},"GIL Disabled (0.8713 秒) \u003C 多線程 (0.8912 秒) \u003C 多進程 (1.0846 秒)",[508,5439,5440,5445,5450],{},[511,5441,5442,5444],{},[3556,5443,5241],{},"：受 GIL 限制，執行速度與單 CPU 執行差不多",[511,5446,5447,5449],{},[3556,5448,5267],{},"：運用多個 CPU 核心加速",[511,5451,5452,5455],{},[3556,5453,5454],{},"GIL Disabled","：運用多個 CPU 核心加速，且避免了多進程管理的額外開銷",[3547,5457,5459],{"id":5458},"io-綁定任務模擬網路請求","I/O 綁定任務（模擬網路請求）",[11,5461,5434,5462],{},[3556,5463,5464],{},"Asyncio (0.0000 秒) \u003C\u003C 多線程 (1.0072 秒) ≈ GIL Disabled (1.0093 秒) ≈ 多進程 (1.1046 秒)",[508,5466,5467,5473],{},[511,5468,5469,5472],{},[3556,5470,5471],{},"多線程、多進程、GIL Disabled","：三者效能差不多",[511,5474,5475,5478,5479,5482],{},[3556,5476,5477],{},"Asyncio","：效能最好，因為測試任務使用 ",[35,5480,5481],{},"await asyncio.sleep","，基本上不會有運行時間開銷",[3533,5484,5485],{"id":5485},"實際應用場景",[11,5487,5488],{},[3556,5489,5490],{},"首先需要考慮業務場景，做這個優化加速是否有需要？如果加速沒有很重要的話就是一個 Nice to have 的優化。",[3547,5492,5494],{"id":5493},"不建議使用-disabled-gil","不建議使用 Disabled GIL",[11,5496,5497],{},"目前 Disabled GIL 還在測試階段，許多套件都還沒完全支援，也需要自己處理變數管理等問題，目前不考慮使用。",[3547,5499,5501],{"id":5500},"適合使用-multiprocessing-的場景","適合使用 Multiprocessing 的場景",[11,5503,5504],{},"非 AI 的大量運算需求，可以使用 Multiprocessing 來加速：",[508,5506,5507,5513],{},[511,5508,5509,5512],{},[3556,5510,5511],{},"售電平台的最佳參數求取","：目前策略使用網格搜索，可以切分網格分配給 CPU 執行",[511,5514,5515,5518],{},[3556,5516,5517],{},"EV 管理平台","：需要定時計算電站使用率",[3547,5520,5522],{"id":5521},"適合使用-asyncio-的場景","適合使用 Asyncio 的場景",[11,5524,5525],{},"網路的大量需求，可以使用 Asyncio 來加速：",[508,5527,5528,5534,5552,5562],{},[511,5529,5530,5533],{},[3556,5531,5532],{},"MQTT / OCPP","：這類 pub/sub 協議",[511,5535,5536,3653,5539],{},[3556,5537,5538],{},"爬蟲或大量 Third-party API 請求",[508,5540,5541],{},[511,5542,5543,5544,5547,5548,5551],{},"使用 ",[35,5545,5546],{},"aiohttp"," 替換 ",[35,5549,5550],{},"requests"," 模組",[511,5553,5554,3653,5557],{},[3556,5555,5556],{},"Database 異步操作",[508,5558,5559],{},[511,5560,5561],{},"pymongo 遷移到 async client (≥ v4.13)",[511,5563,5564,3653,5567],{},[3556,5565,5566],{},"Web Framework",[508,5568,5569],{},[511,5570,5571],{},"Flask 遷移到 FastAPI",[3533,5573,5574],{"id":5574},"參考資料",[508,5576,5577,5584,5591],{},[511,5578,5579],{},[15,5580,5583],{"href":5581,"rel":5582},"https://www.youtube.com/watch?v=brYsDi-JajI",[19],"【python】asyncio的理解與入門，搞不明白協程？看這個視頻就夠了",[511,5585,5586],{},[15,5587,5590],{"href":5588,"rel":5589},"https://www.youtube.com/watch?v=K0BjgYZbgfE&t=94s",[19],"【python】await機制詳解。再來個硬核內容，把並行和依賴背後的原理全給你講明白",[511,5592,5593],{},[15,5594,5597],{"href":5595,"rel":5596},"https://pymongo.readthedocs.io/en/stable/async-tutorial.html",[19],"Async Tutorial - PyMongo 4.14.1 documentation",[1882,5599,5600],{},"html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":33,"searchDepth":48,"depth":48,"links":5602},[5603,5604,5610,5611,5612,5616,5621],{"id":3535,"depth":48,"text":3536},{"id":3545,"depth":48,"text":3545,"children":5605},[5606,5607,5608,5609],{"id":3549,"depth":54,"text":3550},{"id":3601,"depth":54,"text":3602},{"id":3640,"depth":54,"text":3641},{"id":3677,"depth":54,"text":3678},{"id":3699,"depth":48,"text":3699},{"id":3850,"depth":48,"text":3850},{"id":5179,"depth":48,"text":5179,"children":5613},[5614,5615],{"id":5430,"depth":54,"text":5431},{"id":5458,"depth":54,"text":5459},{"id":5485,"depth":48,"text":5485,"children":5617},[5618,5619,5620],{"id":5493,"depth":54,"text":5494},{"id":5500,"depth":54,"text":5501},{"id":5521,"depth":54,"text":5522},{"id":5574,"depth":48,"text":5574},"2025-10-24","介紹 Python 並發處理方法，包括多線程、多進程、asyncio 以及其實務應用。",{},"/blog/concurrency",{"title":3529,"description":5623},"blog/concurrency",[1900,5629,5630,5477],"Concurrency","Threading","kN1Wwn-a_-qug2Xu4sKMYHWVsmetrprGl94eSxUxzbE",{"id":5633,"title":5634,"author":6,"body":5635,"category":1887,"date":5622,"description":6019,"extension":1890,"image":33,"language":1891,"meta":6020,"navigation":180,"path":6021,"seo":6022,"stem":6023,"tags":6024,"updatedAt":1901,"__hash__":6025},"blog/blog/python-gil-introduction.md","Python GIL 介紹",{"type":8,"value":5636,"toc":6007},[5637,5641,5646,5649,5669,5672,5676,5681,5685,5705,5709,5712,5787,5791,5794,5862,5866,5869,5893,5896,5916,5919,5975,5977],[3533,5638,5640],{"id":5639},"什麼是-gil","什麼是 GIL？",[22,5642,5643],{},[11,5644,5645],{},"💡 GIL 是 CPython 解釋器中的一個鎖，確保在任何時刻只有一個線程可以執行 Python 字節碼。",[11,5647,5648],{},"這意味著即使有多個線程，Python 程式也無法真正利用多核心 CPU 實現並行（parallelism），僅能實現並發（concurrency）的假象。GIL 為 Python 提供了以下好處：",[508,5650,5651,5657,5663],{},[511,5652,5653,5656],{},[3556,5654,5655],{},"簡化種族條件（Race Conditions）","：防止Multi thread同時修改共享資料，降低記憶體損壞風險。",[511,5658,5659,5662],{},[3556,5660,5661],{},"簡化垃圾回收（Garbage Collection）","：GIL 使記憶體管理更簡單，無需複雜的鎖機制。",[511,5664,5665,5668],{},[3556,5666,5667],{},"歷史背景","：Python 於 1991 年設計時，多數電腦僅有單核心 CPU，GIL 是當時簡化實現的合理選擇。",[11,5670,5671],{},"然而，GIL 的缺點顯而易見：它限制了多核心 CPU 的利用率，使 Python 在 CPU 密集型任務（如數學計算、資料解析、AI 模型訓練）上的效能不如預期。",[3533,5673,5675],{"id":5674},"為什麼移除-gilpep-703-python-313","為什麼移除 GIL？（PEP 703, Python 3.13）",[22,5677,5678],{},[11,5679,5680],{},"💡 隨著硬體技術的進步（多核心 CPU 普及）和 Python 社群對高效能的需求，GIL 逐漸成為瓶頸。PEP 703（Python 3.13）提出使 GIL 可選，允許程式在編譯時或運行時禁用 GIL，讓Multi thread直接利用操作系統的線程調度器，實現真正的並行。",[3547,5682,5684],{"id":5683},"移除-gil-的動機","移除 GIL 的動機",[508,5686,5687,5693,5699],{},[511,5688,5689,5692],{},[3556,5690,5691],{},"社群需求","：開發者希望 Python 能更快，並充分利用現代多核心硬體。",[511,5694,5695,5698],{},[3556,5696,5697],{},"效能提升","：禁用 GIL 後，某些 CPU 密集型任務（如桶排序、分形生成）可顯著加速。",[511,5700,5701,5704],{},[3556,5702,5703],{},"競爭壓力","：其他語言（如 Go、Rust）支援真正的並行，Python 需跟上時代。",[3547,5706,5708],{"id":5707},"移除-gil-的挑戰","移除 GIL 的挑戰",[11,5710,5711],{},"移除 GIL 並非易事，因為 Python 的許多核心機制依賴 GIL 的保護。以下是主要挑戰：",[1004,5713,5714,5746,5758,5775],{},[511,5715,5716,5719],{},[3556,5717,5718],{},"引用計數（Reference Counting）",[508,5720,5721,5727],{},[511,5722,5723,5726],{},[3556,5724,5725],{},"問題","：傳統的非原子引用計數（non-atomic reference counting）不具線程安全，可能導致種族條件。例如，refcount++ 分三步（讀、加、寫），可能被其他線程中斷。",[511,5728,5729,3653,5732],{},[3556,5730,5731],{},"解決方案",[508,5733,5734,5740],{},[511,5735,5736,5739],{},[3556,5737,5738],{},"原子引用計數","：線程安全，但速度慢 10x-100x。",[511,5741,5742,5745],{},[3556,5743,5744],{},"偏向引用計數（Biased Reference Counting）","：檢查引用是否僅屬於單一線程，若是則使用快速的非原子計數，否則使用原子計數。",[511,5747,5748,5751],{},[3556,5749,5750],{},"垃圾回收（Garbage Collection）",[508,5752,5753],{},[511,5754,5755,5757],{},[3556,5756,5725],{},"：傳統垃圾回收依賴 GIL 保護，需改用延遲引用計數（deferred reference counting）來處理循環引用。",[511,5759,5760,5763],{},[3556,5761,5762],{},"記憶體分配",[508,5764,5765,5770],{},[511,5766,5767,5769],{},[3556,5768,5725],{},"：現有記憶體分配器假設 GIL 保護，不具線程安全。",[511,5771,5772,5774],{},[3556,5773,5731],{},"：開發新的線程安全記憶體分配器，優化列表和字典的快速讀取。",[511,5776,5777,5780],{},[3556,5778,5779],{},"兼容性",[508,5781,5782],{},[511,5783,5784,5786],{},[3556,5785,5725],{},"：許多 C-API 擴展（如 NumPy、Pandas）假設 GIL 存在，需重新編譯以支援無 GIL 環境。",[3533,5788,5790],{"id":5789},"gil-與禁用-gil-的比較","GIL 與禁用 GIL 的比較",[11,5792,5793],{},"以下表格比較了 GIL 和禁用 GIL 的特點：",[3701,5795,5796,5808],{},[3704,5797,5798],{},[3707,5799,5800,5802,5805],{},[3710,5801,3712],{},[3710,5803,5804],{},"啟用 GIL",[3710,5806,5807],{},"禁用 GIL",[3726,5809,5810,5823,5836,5849],{},[3707,5811,5812,5817,5820],{},[3731,5813,5814],{},[3556,5815,5816],{},"並行性",[3731,5818,5819],{},"非真正的並行，僅一個線程執行",[3731,5821,5822],{},"真正的Multi thread並行，利用多核心",[3707,5824,5825,5830,5833],{},[3731,5826,5827],{},[3556,5828,5829],{},"資料共享",[3731,5831,5832],{},"簡單，無需額外鎖",[3731,5834,5835],{},"需小心處理種族條件（如使用 threading.Lock）",[3707,5837,5838,5843,5846],{},[3731,5839,5840],{},[3556,5841,5842],{},"效能",[3731,5844,5845],{},"受限於 GIL，CPU 綁定任務慢",[3731,5847,5848],{},"視程式而定，可能顯著提升（如桶排序、分形生成）",[3707,5850,5851,5856,5859],{},[3731,5852,5853],{},[3556,5854,5855],{},"擴展相容性",[3731,5857,5858],{},"廣泛支援",[3731,5860,5861],{},"需檢查擴展版本（如 Cython、NumPy）",[3533,5863,5865],{"id":5864},"禁用-gil-的推薦場景","禁用 GIL 的推薦場景",[11,5867,5868],{},"禁用 GIL 在以下場景中特別有用：",[508,5870,5871,5877,5882,5887],{},[511,5872,5873,5876],{},[3556,5874,5875],{},"ETL 處理","：資料提取、轉換和載入需要大量計算。",[511,5878,5879,5881],{},[3556,5880,3624],{},"：如濾波、轉換等 CPU 密集型操作。",[511,5883,5884,5886],{},[3556,5885,3627],{},"：處理大量資料並進行模式匹配。",[511,5888,5889,5892],{},[3556,5890,5891],{},"即時分析","：需要快速響應的計算任務。",[3533,5894,5895],{"id":5895},"注意事項",[508,5897,5898,5904,5910],{},[511,5899,5900,5903],{},[3556,5901,5902],{},"Race Condition","：禁用 GIL 後，Multi thread可能同時存取共享資料，導致記憶體損壞。建議使用 threading.Lock 或其他同步機制。",[511,5905,5906,5909],{},[3556,5907,5908],{},"擴展模組相容性","：確認使用的庫（如 NumPy、Pandas、PyTorch）支援無 GIL 環境。",[511,5911,5912,5915],{},[3556,5913,5914],{},"效能不確定性","：禁用 GIL 不保證所有程式都變快，需針對具體任務進行基準測試。",[3533,5917,5918],{"id":5918},"常見誤解與解答",[1004,5920,5921,5935,5945,5955,5965],{},[511,5922,5923,5926,5927],{},[3556,5924,5925],{},"並發(Concurrency)與並行(Parallelism)的區別","：",[508,5928,5929,5932],{},[511,5930,5931],{},"並發是多任務「看似」同時進行，實際上可能是切換執行。",[511,5933,5934],{},"並行是多任務在多核心上真正同時執行。",[511,5936,5937,5940],{},[3556,5938,5939],{},"為什麼 Python 慢？",[508,5941,5942],{},[511,5943,5944],{},"GIL 限制了Multi thread的並行性，導致 CPU 綁定任務無法充分利用多核心。",[511,5946,5947,5950],{},[3556,5948,5949],{},"禁用 GIL 如何管理 CPU 使用？",[508,5951,5952],{},[511,5953,5954],{},"透過操作系統的線程調度器，讓Multi thread在多核心上並行執行。",[511,5956,5957,5960],{},[3556,5958,5959],{},"禁用 GIL 是否總是更快？",[508,5961,5962],{},[511,5963,5964],{},"不一定，效能提升取決於任務類型和程式設計。某些任務（如 I/O 綁定）可能無明顯改善。",[511,5966,5967,5970],{},[3556,5968,5969],{},"簡單資料共享是什麼？",[508,5971,5972],{},[511,5973,5974],{},"指線程間直接存取記憶體的能力，而Multi process需要管道或共享記憶體，較為複雜。",[3533,5976,5574],{"id":5574},[508,5978,5979,5986,5993,6000],{},[511,5980,5981],{},[15,5982,5985],{"href":5983,"rel":5984},"https://peps.python.org/pep-0703/",[19],"PEP 703 – Making the Global Interpreter Lock Optional in CPython",[511,5987,5988],{},[15,5989,5992],{"href":5990,"rel":5991},"https://tw.pycon.org/2025/zh-hant/conference/keynotes#Donghee_Na",[19],"PyCon TW 2025 主題演講",[511,5994,5995],{},[15,5996,5999],{"href":5997,"rel":5998},"https://tw.pycon.org/2025/zh-hant/conference/talk/352",[19],"PyCon TW 2025 - Talk 352",[511,6001,6002],{},[15,6003,6006],{"href":6004,"rel":6005},"https://tw.pycon.org/2025/zh-hant/conference/talk/335",[19],"PyCon TW 2025 - Talk 335",{"title":33,"searchDepth":48,"depth":48,"links":6008},[6009,6010,6014,6015,6016,6017,6018],{"id":5639,"depth":48,"text":5640},{"id":5674,"depth":48,"text":5675,"children":6011},[6012,6013],{"id":5683,"depth":54,"text":5684},{"id":5707,"depth":54,"text":5708},{"id":5789,"depth":48,"text":5790},{"id":5864,"depth":48,"text":5865},{"id":5895,"depth":48,"text":5895},{"id":5918,"depth":48,"text":5918},{"id":5574,"depth":48,"text":5574},"Python 全域直譯器鎖（GIL）介紹",{},"/blog/python-gil-introduction",{"title":5634,"description":6019},"blog/python-gil-introduction",[1900,5302,5630,5629],"1JlER9elCE4iurskWIIr2pl19MOnyKoNU2R4fwmCB4w",1790038954711]