【100天算法入門 - 每日三題 - Day2】二分查找、第一個錯誤的版本、搜索插入比特置

哪 吒 2021-08-15 22:05:24 阅读数:307

本文一共[544]字,预计阅读时长:1分钟~
算法 每日 day2 day 二分

大家好,我是哪吒,一個熱愛編碼的Java工程師,本著“欲速則不達,欲達則欲速”的學習態度,在程序猿這條不歸路上不斷成長,所謂成長,不過是用時間慢慢擦亮你的眼睛,少時看重的,年長後卻視若鴻毛,少時看輕的,年長後卻視若泰山,成長之路,亦是漸漸放下執念,內心歸於平靜的旅程。

也許,我們永遠都不會知道自己能走到何方,遇見何人,最後會變成什麼樣的人,但一定要記住,能讓自己登高的,永遠不是別人的肩膀,而是挑燈夜戰的自己,人生的道路剛剛啟程,當你累了倦了也不要迷茫,回頭看一看,你早已不再是那個年少輕狂的少年。

1、LeetCode 704.二分查找

題目

給定一個 n 個元素有序的(昇序)整型數組 nums 和一個目標值 target  ,寫一個函數搜索 nums 中的 target,如果目標值存在返回下標,否則返回 -1。

小編菜解

public static int search(int[] nums, int target) {
int left = 0;
int right = nums.length - 1;
while (left < right){
int mid = left + (right - left)/2;
if(target == nums[mid]){
return mid;
}else if(target<nums[mid]){
right = mid - 1;
}else if(target>nums[mid]){
left = mid+1;
}
}
return -1;
}

大神解法

public int search(int[] nums, int target) {
int left = 0;
int right = nums.length - 1;
while (left <= right){
int mid = left + (right - left)/2;
if(target == nums[mid]){
return mid;
}else if(target<nums[mid]){
right = mid - 1;
}else if(target>nums[mid]){
left = mid+1;
}
}
return -1;
}

總結

差了一個等號,差之毫厘謬以千裏啊。

2、LeetCode 278.第一個錯誤的版本

題目

你是產品經理,目前正在帶領一個團隊開發新的產品。不幸的是,你的產品的最新版本沒有通過質量檢測。由於每個版本都是基於之前的版本開發的,所以錯誤的版本之後的所有版本都是錯的。

假設你有 n 個版本 [1, 2, ..., n],你想找出導致之後所有版本出錯的第一個錯誤的版本。

你可以通過調用 bool isBadVersion(version) 接口來判斷版本號 version 是否在單元測試中出錯。實現一個函數來查找第一個錯誤的版本。你應該盡量减少對調用 API 的次數。

示例

輸入:n = 5, bad = 4
輸出:4
解釋:
調用 isBadVersion(3) -> false 
調用 isBadVersion(5) -> true 
調用 isBadVersion(4) -> true
所以,4 是第一個錯誤的版本。

思路及算法

因為題目要求盡量减少調用檢查接口的次數,所以不能對每個版本都調用檢查接口,而是應該將調用檢查接口的次數降到最低。

注意到一個性質:當一個版本為正確版本,則該版本之前的所有版本均為正確版本;當一個版本為錯誤版本,則該版本之後的所有版本均為錯誤版本。我們可以利用這個性質進行二分查找。

這樣我們每判斷一次都可以縮緊一次邊界,而每次縮緊時兩邊界距離將變為原來的一半,因此我們至多只需要縮緊 O(\log n)O(logn) 次。

小編菜解

public class Solution extends VersionControl {
public int firstBadVersion(int n) {
int left = 1, right = n;
while (left < right) { // 循環直至區間左右端點相同
int mid = left + (right - left) / 2; // 防止計算時溢出
if (isBadVersion(mid)) {
right = mid; // 答案在區間 [left, mid] 中
} else {
left = mid + 1; // 答案在區間 [mid+1, right] 中
}
}
// 此時有 left == right,區間縮為一個點,即為答案
return left;
}
}

複雜度分析

  • 時間複雜度:O(\log n)O(logn),其中 nn 是給定版本的數量。

  • 空間複雜度:O(1)O(1)。我們只需要常數的空間保存若幹變量。

3、LeetCode 35.搜索插入比特置

題目

給定一個排序數組和一個目標值,在數組中找到目標值,並返回其索引。如果目標值不存在於數組中,返回它將會被按順序插入的比特置。

請必須使用時間複雜度為 O(log n) 的算法。

小編菜解

/**
* 輸入: nums = [1,3,5,6], target = 5
* 輸出: 2
*
* 輸入: nums = [1,3,5,6], target = 2
* 輸出: 1
*/
public static int searchInsert(int[] nums, int target){
for (int i = 0; i < nums.length; i++) {
if(nums[i] == target){
return i;
}
}
for (int i = 0; i < nums.length; i++) {
if(nums[i] < target){
if(i < nums.length - 1 && nums[i+1] > target){
return i+1;
}
if(nums[nums.length - 1] <target){
return nums.length;
}
}else if(nums[0] > target){
return 0;
}
}
return -1;
}

 解題思路

題意為尋找一個目標值,此類問題都可以使用二分查找。

大神解法

public static int searchInsert2(int[] nums, int target){
int n = nums.length;
int left = 0;
int right = n - 1;
int index = n;
while (left <= right){
int mid = left + (right - left)/2;
if (target <= nums[mid]) {
index = mid;
right = mid - 1;
}else{
left = mid + 1;
}
}
return index;
}

上一篇:【100天算法入門 - 每日三題 - Day1】二叉樹的中序遍曆、兩數之和、整數反轉

下一篇:【100天算法入門 - 每日三題 - Day3】回文數、羅馬數字轉數字、最大公共前綴

往期精彩內容:

Java知識體系總結

【全棧最全Java框架總結】SSH、SSM、Springboot

超詳細的springBoot學習筆記

常見數據結構與算法整理總結

Java設計模式:23種設計模式全面解析

Java面試題總結(附答案)

10萬字208道Java經典面試題總結(附答案,建議收藏)

MySql知識體系總結

Linux知識體系總結

【Vue基礎知識總結 1】Vue入門

Redis知識體系總結

版权声明:本文为[哪 吒]所创,转载请带上原文链接,感谢。 https://gsmany.com/2021/08/20210815220515734R.html