From 38315584ad6f111bf4a3d922d7c2f2c45d01f06e Mon Sep 17 00:00:00 2001 From: labuladong Date: Fri, 28 Feb 2020 18:56:02 +0800 Subject: [PATCH 1/4] =?UTF-8?q?=E4=BF=AE=E6=94=B9translateIssue=E6=A8=A1?= =?UTF-8?q?=E6=9D=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/ISSUE_TEMPLATE/others.md | 10 ++++++++++ .github/ISSUE_TEMPLATE/translate.md | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) create mode 100644 .github/ISSUE_TEMPLATE/others.md diff --git a/.github/ISSUE_TEMPLATE/others.md b/.github/ISSUE_TEMPLATE/others.md new file mode 100644 index 0000000..f03e25e --- /dev/null +++ b/.github/ISSUE_TEMPLATE/others.md @@ -0,0 +1,10 @@ +--- +name: 其他issue +about: 我还有一些其他的建议/问题 +title: '' +labels: '' +assignees: '' + +--- + + diff --git a/.github/ISSUE_TEMPLATE/translate.md b/.github/ISSUE_TEMPLATE/translate.md index f633c9f..c11e7fc 100644 --- a/.github/ISSUE_TEMPLATE/translate.md +++ b/.github/ISSUE_TEMPLATE/translate.md @@ -2,7 +2,7 @@ name: 参与翻译 about: 我想参与仓库中文章的翻译工作 title: 'translate ' -labels: documentation +labels: translate assignees: '' --- From f34e316c73ceeb034e69807d1e6d5ae9ae7d103c Mon Sep 17 00:00:00 2001 From: labuladong Date: Fri, 28 Feb 2020 20:52:59 +0800 Subject: [PATCH 2/4] =?UTF-8?q?=E4=BF=AE=E6=94=B9=20translate=20=E8=A7=84?= =?UTF-8?q?=E5=88=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/ISSUE_TEMPLATE/translate.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/translate.md b/.github/ISSUE_TEMPLATE/translate.md index c11e7fc..7bb442c 100644 --- a/.github/ISSUE_TEMPLATE/translate.md +++ b/.github/ISSUE_TEMPLATE/translate.md @@ -9,7 +9,9 @@ assignees: '' @@ -21,3 +23,7 @@ assignees: '' 我准备将它翻译成:**英文** **预计 X 天内翻译完成**,若由于种种原因没有完成,如果你愿意,你可以接替我的工作翻译这篇文章。 + + + + \ No newline at end of file From 2e34052392660f0f54519951f49d504e65448743 Mon Sep 17 00:00:00 2001 From: labuladong Date: Fri, 28 Feb 2020 21:32:23 +0800 Subject: [PATCH 3/4] =?UTF-8?q?=E4=BF=AE=E6=94=B9=20translate=20issue=20?= =?UTF-8?q?=E6=A8=A1=E6=9D=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/ISSUE_TEMPLATE/translate.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/translate.md b/.github/ISSUE_TEMPLATE/translate.md index 7bb442c..16da565 100644 --- a/.github/ISSUE_TEMPLATE/translate.md +++ b/.github/ISSUE_TEMPLATE/translate.md @@ -22,8 +22,10 @@ assignees: '' 我准备将它翻译成:**英文** -**预计 X 天内翻译完成**,若由于种种原因没有完成,如果你愿意,你可以接替我的工作翻译这篇文章。 +**预计 X 天内翻译完成**,若由于种种原因,规定时间已过但此 issue 还未提交 pull request,则此 issue 自动失效。如果你愿意,你可以新开一个 issue 接替我的工作翻译这篇文章。 - + - \ No newline at end of file + + + \ No newline at end of file From ec3921c16de98f261d171a7780b9b7a5b16c4676 Mon Sep 17 00:00:00 2001 From: sinjoywong Date: Sun, 1 Mar 2020 22:16:23 +0800 Subject: [PATCH 4/4] binary search translate --- .DS_Store | Bin 0 -> 8196 bytes 算法思维系列/.DS_Store | Bin 0 -> 8196 bytes 算法思维系列/BinarySearch.md | 301 +++++++++++++++++++++++++++++ 3 files changed, 301 insertions(+) create mode 100644 .DS_Store create mode 100644 算法思维系列/.DS_Store create mode 100644 算法思维系列/BinarySearch.md diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..c5b73a50c5751e5579f5bac051fb46a4548c81d9 GIT binary patch literal 8196 zcmeHMU2GIp6h3DuWu_D8w4!ZcCoGhoN@{;-Lm>!mciTW)piQ^X^4retjP1nPnRREj zr7W#A!3RYRzK9SFQC~oPw4gru!-GT<2{C%^%xu$c0mF;IFgLmP z+bi$?1(LsRz>K zY^PA4-T{tH$fIG8PPo)DC7Oq3>>yeL zNl@5}e}=^uc@~A;X9n=u3*DthZg!W=)`d-Zx`Ft_VC`%jEX&g=R8t9K{LCoMUcvmr1sqqz6)h|}5F0W_Vzz8& ztcaZ6$3|VUJrwu)J*KHo_vQF*O&#eM7e`IQmNi37JI0!#lFI&G%}~sdh?y}I%kdL) z1sun7e7{(p%{DgGSBDzw>&L1?*`}sC>Nl((8{@gMRrQIvrGaXOb2--7bIUK2n(h5j`r<4cJ_;6#!|agUADDhwMDj7t6wa( zDB`w+X>_I4VT!IdVd|NrL6VY$tS2(0tTyX_cbS%EYo@WM&sGoFOvW6| z67}u1%(NYKob_qs-_r}B=Qu@GRLD);# zGi>c~O-=6_(G+`Vk8CAWL(z=E-eJws;=0;n$Vs&Xt9gE^xV&P?(x4>WPPH!+*PhI1 z_NZ9NaZ{yYNwKh8s^rBT0!V}f2h4vMTO@a)`pFO)I02kDt36x&5H%8FJUH=6rx2u zwje1YwQ%C6+(9<+cGsC8FDb7mrX_9TxIIkLtSG9&Rp#(e8Lo1>PBJRPb?!)H zx3L6u5P^0$NTSK(@` z#X4Mv4H(8YY{w4l#Q{`t5Qk91G>+gX9>y#l#pm#Od;wp?6L=b5$2agzd9H`}>!Jx=6$2r5*YiJmtJ;6;eUqW@Th9|I#^PFL@UTEM5*5Z6u zx?b486Y#|XSGq~q%n`oDLRTsY%{(uH<2Sk{D2PbM;J=~vj+ng&U%`*?D_nyc@E6X< zA}qrYR$&cpz%BR~Mlg!4xD&gu8)Mjm2e2PyjAH_IOrnV?LTwh0;5a^oPZMg7IjB93 zC-D@%imwrR&)`{n%R%pXd=KBp4+y=VKypoUA;aJ+xO=FPw4Bv&PzJ2AT z6Y*o0=iXj$mgF<YX0)s zTRTK`fGR6YZ^EUH2{q1hoT&30Cp!HPL+Xb}mDz+nI^j~{Q2Eb)2=M-r_wRrI{=c8^ G|9=3&zX+xP literal 0 HcmV?d00001 diff --git a/算法思维系列/.DS_Store b/算法思维系列/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..ae719c80615e65c123f26d17aea3dfd35773338d GIT binary patch literal 8196 zcmeHMO=uHA6n>Kwv!VV}J+v2LPZB%`iic7WVn`*@W~13?m9}Y`AKO5FN;DCz)SwY9 zjVRLE=ut!}9z1&!1VOQgh~P<-qP^8ad)N17SKUo!izgAC2{Yg9?tJf?`7)F65&&R< za(WLy7XT<&2|L=c5fpk(wWYYsJDrFO`2Zz22RdY66nnBr2c!ei0qKBrKsxX@I)LBV zR1}BredDQYr32D||Iz{ad{D6x`c14F$Ui!;;VA%O8{Xyx`DGZN9Z@J=#+(lv=oagmht_kcFytpR{^( z!`SEK)OtGLvpO63G{lDcPY#erA`RDQlg6f_AGKZjVr6amMWvR#bo%PLOskd>4PS&< zJy{)I7An0)CF^*v-ZQtR-M{_ZNrCSZD`PV;>hAahVrYGI6;t9Bk(&EJlbWKxN_l3l zIn54mhuFN{c>F`*@sGV6S(&+43W;>+MA%lP3=T~0)b?s8@Ld(`WIiwJ-rqWSN=sxW zQiZ9vW3^bF6f3p6?=zvy6LAC=`Dl&cjdz!Qm0Bd6UW^QhH0ku%=IF_Hmiqa=6U>mW z$QHlwCc1EbUSD$Zj!uU?{>1W~3#nW28;-NF#iyB&3tHdxuObGW9@~mNH@A&Moz4J% zC#|~%$+AcXqyshw+{RTG<^R3TzyI4f@ Although the basic idea of binary search is comparatively straightforward, the details can be surprisingly trickey... + +This article is going to discuss several the most commonly used binary search scenes: to find a number, to find its left boundary, to find its right boundary. +And that we are going to discuss details, such as if inequality sign should with the equal sign, if mid should plus one, etc. +After analysing the difference of these details and the reason why them come out, you can write binary search code flexibly and accuratly. + +### Part zero: The Framework of Binary Search + +```java +int binarySearch(int[] nums,int target){ + int left = 0,right = ...; + while(...){ + int mid = (right + left) / 2; + if(nums[mid] == target){ + ... + }else if(nums[mid] < target){ + left = ... + }else if(nums[mid] > target){ + right = ... + } + } + return ...; +} +``` + +**A technique to analize binary search is: use `else if`, rather than using `else`, then we can manage all the details.** + +In order to make it more simplier to understand, this article will use `else if` all along, you can optimize it after you truly understand it. + +Hint: the `...` part is where we need focus to. When you implement binary search, pay attention to these parts firstly. We are going to analyze how it changes under sepecific circumastance. + +Noted: when we calculate `mid`, we need to prevent it overflowing. You can see previous article, and here we assume you can handle it. + +### 1. Find a number (Basic Binary Search) + +This is the simpliest scene, we are going to search a number in a array. If it exists, return its index, otherwise return `-1`. + +```java +int binarySearch(int[] nums,int target){ + int left = 0; + int right = nums.length - 1; //pay attention! + + while(left <= right){ + int mid = (right + left) / 2; + if(nums[mid] == target){ + return mid; + }else if(nums[mid] < target){ + left = mid + 1; + }else if(nums[mid] > target){ + right = mid - 1; + } + } + return -1; +} +``` + +#### Q1.Why using `<=` in `while` loop rather than `<`? + +>A1: Because when we initialize `right`, we set it to `nums.length - 1`, which is index of the last element, not `nums.length`. + +Both of them may show up in different binary search implementions, here is diffenences: With the former, both ends are closed, like `[left,right]`, and the later is left open right close interval, like `[left,right)`, so when we use index `nums.length`, it will out of bounds. + +We will use the former `[left,right]` implemention, which both ends are closed. **This is actually the interval we search every time**. + +So when we should stop searching? + +Of course we can stop when we find the target number in the array: + +```java + if(nums[mid] == target){ + return mid; + } +``` + +But if we havn't find it, we'll need to terminate `while` loop and return `-1`. +So when we should terminal `while` loop? That's simple, **when the search inverval is empty, we should stop searching**, which means we have search all items and have nothing left, we just can't find target number in the array. + +The terminal condition of `while(left <= right)` is `left == right + 1`, we can write it as inverval `[right + 1,right]`, or we can just put a specific number into it, like `[3,2]`. It's obvious that **the inverval is empty**, since there is no number which is larger than 3 and less-and-equal to 2. So we should terminate `while` loop and return -1; + +The terminal condition of `while(wlft < right)` is `left == right`, we can write is as interval `[left,right]`, or we can also put a specific number into it, like `[2,2]`, **the interval is NOT empty**, there is still a number `2`, but the `while` loop is terminated, which means the interval `[2,2]` is missed, index 2 is not been searched, it's wrong when we return -1 directly. + +It is allright if you want to use `while(left < right)` anyway. Since we know how the mistake occurred, we can fix it with a patch: + +```java + //... + while(left < right){ + //... + } + return nums[left] == target ? left : -1; +``` + +#### Q2: Why we implement it as `left = mid + 1`,`right = mid - 1`? I read others' code and they are implenting it as `right = mid` or `left = mid`, there is not so plus or minus, what's the difference? + +>A2: This is also a difficulty of Binary Search implemention. But you can handle it if you can understand previous content. + +We are aware of the concept of 'Search Interval' now, and in our implementation, the search intarval is both end closed, like `[left, right]`. So when we find index `mid` isn't the `target` we want, how to determine next search interval? + +It is obviously that we will use `[left,mid - 1]` or `[mid + 1, right]`: we have just searched `mid`, so it should be removed from search interval. + +#### Q3: What's the defects of this algorithm? + +>A3: Since then, you should have already mastered all details of Binary Search, along with the reason why it works that way. However, there are some defects still. + +For example, there is a sorted array `nums = [1,2,2,2,3]`, `targe = 2`, after processed with Binary Search Algorithm, we will get result `index = 2`. But if we want to get left boundary of `target`, which is `index = 1`, or if we want to get right boundary of `target`, which is `index = 3`, we cannot handle it with this algorithm. + +It's a quite normal demand. Perhaps you would say, can't I find a target, then I search it from target to left(or right)? Sure you can, but it's not so good, since we cannt guarantee the time complexity with O(logn). + +Here we will discuss this two kind of Binary Search Alghrithm. + +### Part 2. Binary Search to look for left border + +See codes below, and pay attention to marked details: + +```java +int left_bound(int[] nums,int target){ + if(nums.lengh == 0) return -1; + int left = 0; + int right = nums.length; // Attention! + + while(left < right){ // Attention + int mid = (left + right) / 2; + if(nums[mid] == target){ + right = mid; + }else if(nums[mid] < target){ + left = mid + 1; + }else if(nums[mid] > target){ + right = mid; // Attention + } + } + return left; +} +``` +#### Q1: Why we use `while(left < right)`, rather than `<=`? + +>A1: Analyze in the same way, since `right = nums.length` rather than `nums.length - 1`, the search interval is `[left, right)`, which is left closed right open. + +>The terminal condition of `while(left < right)` is `left == right`. At this time search interval `[left,right)` is empty, so it can be terminated correctly. + +#### Q2: Why there is no `return -1`? what if there is no `target` in `nums`? + +>A2: Before this, let's think about what's meaning of `left border` is: + +![](../pictures/%E4%BA%8C%E5%88%86%E6%9F%A5%E6%89%BE/binarySearch1.png) + +For this array, the algorithm will get result `1`. The result `1` can be interpreted this way: there is 1 element in `nums` which element is less than 2. + +For example, a sorted array `nums = [2,3,5,7]`, `target = 1`, the alghrithm will return 0, which means there is 0 element in `nums` which element is less than 1. + +For example, we have same sorted array as described above, and this time we have `target = 8`, the algorithm will get result `4`, which means there is 4 element in `nums` which element is less than `8`. + +In summary, we can see the interval of return value using the alghrithm (which is the value of `left`) is closed interval `[0,nums.length]`, so we can simply add two line of codes to get `-1` result in proper time. + +```java +while(left < right){ + //... +} +//target is larger than all nums +if(left == nums.length) return -1; +//just like the way previously implenented +return nums[left] == target ? left : -1; +``` + +#### Q1: Why `left = mid + 1, right = mid`? It's kind of different with previous implement. + +>A1: It's easy to explain. Since our search interval is [left,right), which is left closed right open, so when `nums[mid]` has been detected, in then next move, the search interval should remove `mid` and slit it to two intervals, which is `[left,mid)` and `[mid + 1, right)`. + +#### Q4: Why this algorithm can be used for search left border? + +>A4: The key is the solution when we meet `nums[mid] == target`: +```java + if (nums[mid] == target){ + right = mid; + } +``` + +>It's obviously that we don't return it immediatly when we find `target`, in the further we continuly search in interval `[left,mid)`, which is search towarding left and contract, then we can get left border. + +#### Q5: Why return `left`, rather than `right`? + +>A5: It's same way, because the terminal condition of `while` is `left == right`. + +### Part Three: BINARY SEARCH TO FIND RIGHT BORDER + +It's almost same with part two: binary search to find left border, there is only two differences, which is marked below: + +```java +int right_bound(int[] nums,int target){ + if(nums.length == 0) return -1; + int left = 0, right = nums.length; + + while(left < right){ + int mid = (left + right) / 2; + if(nums[mid] == target){ + left = mid + 1; // Attention! + }else if(nums[mid] < target){ + left = mid + 1; + }else if(nums[mid] > target){ + right = mid; + } + } + return left - 1; //Attention! +} +``` + +#### Q1: Why this alghrithm can be used to find right border? + +>A1: Similarly, key point is: + +```java + if(nums[mid] == target){ + left = mid + 1; + } +``` + +>When `nums[mid] == target`, we don't return immediately. On the contrary we enlarge the lower bound of search interval, to make serach interval move to right rapidlly, and finally we can get right border. + +#### Q2: Why we return `left -1`, unlike when we process with left border algorithm and return `left`? In addition I think since we are searching right border, shouldn't we return `right` instead? + +>A2: First of all, the terminal condition of `while` loop is `left == right`, so it's right to use both of them. You can return `right - 1` if you want to reflect `right`. + +>As for why we should minus `1` here, it's a special point, let's see the condition judgement: + +```java + if(nums[mid] == target){ + left = mid + 1; + //Thinking this way: mid = left - 1 + } +``` +![](../pictures/%E4%BA%8C%E5%88%86%E6%9F%A5%E6%89%BE/binarySearch2.png) + +When we update the value of `left`, we must do it this way: `left = mid + 1`, which means when `while` is terminated, `nums[left]` must not equal to `target`, but `nums[left-1]` could be equal to `target`. + +As for why `left = mid + 1`, it's same as part two. + +#### Q3: Why there is no `return -1`? what if there is no `target` in `nums`? + +>A3: Like left border search, because the terminal condition of `while` is `left == right`, which means value interval of `left` is `[0,nums.length]`, so we can add some codes and `return -1` apprapoly: + +```java +while(left < right){ + // ... +} +if (lef == 0) return -1; +return nums[left -1] == target ? (left -1) : -1; +``` + +### Part Four: Summary + +Let's tease out the causal logic of these detailed differences. + +#### Firstly, we implement a basic binary search alghrithm: + +Because we initialize `right = nums.length - 1`, it decided our search interval is `[left,right]`, and it also decided `left = mid + 1` and `right = mid - 1`. + +Since we only need to find a index of `target`, so when `nums[mid] == target`, we can return immediately. + +#### Secondly, we implement binary search to find left border: + +Because we initialize `right = nums.length`, it decided our search interval is `[left,right)`, and it also decided `while (left < right)` ,and `left = mid + 1` and `right = mid`. + +Since we need to find the left border, so when `nums[mid] == target`, we shouldn't return immediately, we need to tighten the right border to lock the left border. + +#### Thirdly, we implement binary search to find right border: + +Because we initialize `right = nums.length`, it decided our search interval is `[left,right)`, + +it also decided `while(left < right)`, +`left = mid + 1` and `right = mid`. + +Since we need to find the left border, so when `nums[mid] == target`, we shouldn't return immediately, we need to tighten the left border to lock the right border. + +For further consideration, we must set `left = mid + 1` when we tighten left border, so no matter we return `left` or `right`, we must `minus 1` with the result. + +If you can understand all above, then congratulations, binary search alghrithm won't borther you any more! + +According to this article, you will learn: + +1. When we write binary search code, we don't use `else`, we will use `else if` instead to make our mind clear. + +2. Pay attention to search interval and terminal condition of `while`. If there are any element missed, check it before we return the result. + +3. If we need to search left/right border, we can get proper result when `nums[mid] == target`, and when we search right border, we should minus 1 to get result. + +4. If we close both sides of border, we can only change the code in `nums[mid] == target` and return logic to get right answer. **Put it on your notes, it can be a template for binary search implementation!**