99 lines
3.1 KiB
Markdown
Executable File
99 lines
3.1 KiB
Markdown
Executable File
---
|
|
author: "Devoalda"
|
|
authorEmoji: 🐺
|
|
title: "Leetcode First Bad Version (278)"
|
|
date: 2023-02-18T08:39:33+08:00
|
|
description: Leetcode Challenge 278
|
|
draft: false
|
|
hideToc: false
|
|
enableToc: true
|
|
enableTocContent: true
|
|
tocPosition: inner
|
|
tocLevels: ["h1", "h2", "h3"]
|
|
math: true
|
|
libraries: mathjax
|
|
tags:
|
|
- leetcode
|
|
- python
|
|
series:
|
|
-
|
|
categories:
|
|
- LeetCode
|
|
- python
|
|
image:
|
|
---
|
|
|
|
# Introduction
|
|
|
|
You are a product manager and currently leading a team to develop a new product. Unfortunately, the latest version of your product fails the quality check. Since each version is developed based on the previous version, all the versions after a bad version are also bad.
|
|
|
|
Suppose you have `n` versions `[1, 2, ..., n]` and you want to find out the first bad one, which causes all the following ones to be bad.
|
|
|
|
You are given an API bool `isBadVersion(version)` which returns whether version is bad. Implement a function to find the first bad version. You should minimize the number of calls to the API.
|
|
|
|
{{< tabs Example_1 Example_2 >}}
|
|
{{< tab >}}
|
|
|
|
```shell
|
|
Input: n = 5, bad = 4
|
|
Output: 4
|
|
Explanation:
|
|
call isBadVersion(3) -> false
|
|
call isBadVersion(5) -> true
|
|
call isBadVersion(4) -> true
|
|
Then 4 is the first bad version.
|
|
```
|
|
|
|
{{< /tab >}}
|
|
|
|
{{< tab >}}
|
|
|
|
```shell
|
|
Input: nums = [-1,0,3,5,9,12], target = 2
|
|
Output: -1
|
|
Explanation: 2 does not exist in nums so return -1
|
|
```
|
|
|
|
{{< /tab >}}
|
|
{{< /tabs >}}
|
|
|
|
# Process
|
|
|
|
Using a binary search done in [Leetcode Binary Search 704]( {{< ref "posts/Leetcode-BinarySearch704.md" >}}), I was able to get the first bad version.
|
|
|
|
First, I initialised my `left` variable to `1` as the lower limit was `1` and I couldn't start from 0. I initialised right to be `n` for the number of versions.
|
|
|
|
In the same while loop, I calculated the mid index again, but this time with right shift. I first checked with the `isBadVersion` API for the midpoint. If it is true, I'll set the `firstIndex` variable to the midpoint, and the right index to `mid - 1` to check the left side.
|
|
|
|
If the first condition is not met, I'll check the next half by updating `mid + 1` in the while loop.
|
|
|
|
At the end of the loop, `firstIndex` is returned as the First Bad Version.
|
|
|
|
This solution takes a Time Complexity of $O(\log n)$ and Space Complexity of $O(1)$
|
|
|
|
# Solution
|
|
|
|
```python
|
|
# The isBadVersion API is already defined for you.
|
|
# def isBadVersion(version: int) -> bool:
|
|
|
|
class Solution:
|
|
def firstBadVersion(self, n: int) -> int:
|
|
left = 1
|
|
right = n
|
|
firstIndex = -1
|
|
|
|
while left <= right:
|
|
mid = (left + right) >> 1
|
|
if isBadVersion(mid):
|
|
firstIndex = mid
|
|
right = mid - 1
|
|
else:
|
|
left = mid + 1
|
|
return firstIndex
|
|
```
|
|
|
|
# Afterthoughts
|
|
|
|
This is almost a duplicate of [Leetcode Binary Search 704]( {{< ref "posts/Leetcode-BinarySearch704.md" >}}), where binary search is used as the most efficient algorithm, splitting the sorted array into half each time through the iteration to search for the values required. I need more practice to be familiar and comfortable with these searching algorithms.
|