文章链接
数组(array)是存放在连续内存空间上的相同数据的集合。
关于数组需要注意的点:
题目链接 | 文章链接 | 视频链接 |
题目要求从一个被从小到大排列好且唯一的数组里找到目标(target) with O(log N) runtime complexity.
找到目标返回目标index,目标不存在则返回-1
二分法需要三个点:左边界,中间点,右边界,通过这三个点与目标进行对比从而把数组分段,锁定搜索区域,起到提高效率的作用。Brute force搜索此题会需要 O(N)
class Solution(object):
def search(self, nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: int
"""
left = 0
right = len(nums) - 1
while (left <= right):
mid = int(left + (right - left) / 2)
if nums[mid] == target:
return mid
elif nums[mid] > target:
right = mid - 1
else:
left = mid + 1
return -1
class Solution(object):
def BFS(self, nums, left, right, target):
if (left > right):
return -1
mid = int(left + (right - left) / 2)
if nums[mid] == target:
return mid
if nums[mid] > target:
return self.BFS(nums, left, mid - 1, target)
else:
return self.BFS(nums, mid+1, right, target)
return -1
def search(self, nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: int
"""
return self.BFS(nums, 0, len(nums)-1, target)
class Solution {
public:
int search(vector& nums, int target) {
int left = 0;
int right = nums.size() - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (nums[mid] == target){
return mid;
} else if (nums[mid] > target){
right = mid - 1;
} else {
left = mid + 1;
}
}
return -1;
}
};
class Solution {
public:
int BFS(vector& nums, int left, int right, int target){
if (left > right){
return -1;
}
int mid = left + (right - left) / 2;
if (nums[mid] == target){
return mid;
} else if (nums[mid] > target){
return BFS(nums, left, mid - 1, target);
} else {
return BFS(nums, mid + 1, right, target);
}
}
int search(vector& nums, int target) {
return BFS(nums, 0, nums.size()-1, target);
}
};
int search(int* nums, int numsSize, int target){
int left = 0;
int right = numsSize - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (nums[mid] == target){
return mid;
} else if (nums[mid] > target){
right = mid - 1;
} else {
left = mid + 1;
}
}
return -1;
}
int BFS(int* nums, int left, int right, int target){
if (left > right){
return -1;
}
int mid = left + (right - left) / 2;
if (nums[mid] == target){
return mid;
} else if (nums[mid] > target){
return BFS(nums, left, mid - 1, target);
} else {
return BFS(nums, mid + 1, right, target);
}
}
int search(int* nums, int numsSize, int target){
return BFS(nums, 0, numsSize-1, target);
}
需要注意的点:
题目链接 | 文章链接 | 视频链接 |
从一个数组中原地移除所有等于val的元素并返回移除后的数组长度k。
因为题目很明确说了新数组size k之后的元素是什么没有意义,是什么都无所谓,所以很快就想到了如何解答这道题,看了文章和视频解析才知道这种方法属于“双指针”,可谓是误打误撞完成了要求。
class Solution(object):
def removeElement(self, nums, val):
"""
:type nums: List[int]
:type val: int
:rtype: int
"""
k = 0
for i in range(len(nums)):
if nums[i] != val:
nums[k] = nums[i]
k+=1
return k
class Solution {
public:
int removeElement(vector& nums, int val) {
int k = 0;
for (int i = 0; i < nums.size(); i++){
if (nums[i] != val){
nums[k] = nums[i];
k++;
}
}
return k;
}
};
int removeElement(int* nums, int numsSize, int val){
int k = 0;
for (int i = 0; i < numsSize; i++){
if (nums[i] != val){
nums[k] = nums[i];
k++;
}
}
return k;
}
题目链接
排序好的且唯一的数组和目标,如果找到目标返回目标index,否则返回目标应该被插入的index位置,runtime必须符合O(log N)。
这题与704其实基本相同,只不过需要在找不到目标时返回插入目标所需要的index位置,回想我们的代码,while loop condition (left <= right),在最后一次进入循环时:
也就是说:
mid == left + (right - left) / 2 = left
进入if判断,如果此时target比nums[mid]大,left最终会为mid+1,target确实应该在这里插入
如果此时target比nums[mid]小,right = mid - 1 = left - 1, target则应该在此时的left位置插入,因为在这次循环中我们发现nums[left] == nums[mid] > target,所以我们的function应该return left,而不是right (此前的循环中判断过了nums[left - 1] < target)。
class Solution(object):
def searchInsert(self, nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: int
"""
left = 0
right = len(nums) - 1
while left <= right :
mid = int(left + (right - left)/2)
if nums[mid] == target:
return mid
elif nums[mid] > target:
right = mid - 1
else:
left = mid + 1
return left
题目链接 | 文章链接
一个按照非递减顺序排列的整数数组(并没有说是否唯一)和一个目标,找到目标在该数组开始与结束位置,若没有找到则返回 [-1, 1],runtime必须符合O(log N)。
写了一个O(N)的解法,没想到testcase过了,看来leetcode的testcase也不是很精准,也可能是我对Big O概念还是不熟悉,以下是我的O(N)解法:
class Solution(object):
def searchRange(self, nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: List[int]
"""
start = 0
count = 0
for i in range(len(nums)):
if (nums[i] == target):
if start == 0 and count == 0:
start = i
count += 1
end = start + count - 1
if count != 0:
return [start, end]
else:
return [-1, -1]
这题的关键点在于元素非唯一同时要求O(logN)的运算速度,所以需要使用二分法进行解答,但需要一定的改写。
我们需要两个点:
class Solution(object):
def searchRange(self, nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: List[int]
"""
left = 0
right = len(nums) - 1
while (left <= right):
mid = int(left + (right - left) / 2)
if nums[mid] == target:
start = end = mid
while start >= 0 and nums[start] == target:
start-=1
while end <= len(nums)-1 and nums[end] == target:
end+=1
return [start+1, end-1]
elif nums[mid] > target:
right = mid - 1
else:
left = mid + 1
return [-1, -1]
class Solution(object):
def lower_bound(self, nums, target):
left = 0
right = len(nums) - 1
while left <= right:
mid = int((left + right) / 2)
if nums[mid] < target:
left = mid + 1
else:
right = mid - 1
return left
def searchRange(self, nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: List[int]
"""
start = self.lower_bound(nums, target)
if start == len(nums) or nums[start] != target:
return [-1, -1]
end = self.lower_bound(nums, target + 1) - 1
return [start, end]
写到这里才发现在Python中可以使用mid = (left + right) // 2,因为//与/是有不同的: