数组是存放在连续内存空间上的相同类型的数据的集合,数组可以通过下标索引的方式获取到下标下对应的数据。
**数组的元素是不能删的,只能覆盖。**地址为16进制,二维数组地址是连续一条线的。
像Java是没有指针的,同时也不对程序员暴露其元素的地址,寻址操作完全交给虚拟机,所以看不到每个元素的地址情况。
public static void test_arr() {
int[][] arr = {{1, 2, 3}, {3, 4, 5}, {6, 7, 8}, {9,9,9}};
System.out.println(arr[0]);
System.out.println(arr[1]);
System.out.println(arr[2]);
System.out.println(arr[3]);
}
[I@7852e922
[I@4e25154f
[I@70dea4e
[I@5c647e05
这里的数值也是16进制,这不是真正的地址,而是经过处理过后的数值了,我们也可以看出,二维数组的每一行头结点的地址是没有规则的,更谈不上连续。
前提是数组为有序数组,同时题目还强调数组中无重复元素,因为一旦有重复元素,使用二分查找法返回的元素下标可能不是唯一的,这些都是使用二分法的前提条件。
写二分法,区间的定义一般为两种,左闭右闭即[left, right],或者左闭右开即[left, right)。
定义target在[left, right]区间
if (nums[middle] > target), right 要赋值为 middle - 1,因为当前这个nums[middle]一定不是target,那么接下来要查找的左区间结束下标位置就是 middle - 1
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:
middle = left + (right - left) // 2
if nums[middle] > target:
right = middle-1
elif nums[middle] < target:
left = middle + 1
else:
return middle
return -1
定义 target 是在一个在左闭右开的区间里
while (left < right),这里使用 < ,因为left == right在区间[left, right)是没有意义的
因为当前nums[middle]不等于target,去左区间继续寻找,而寻找区间是左闭右开区间,所以right更新为middle
注:左闭右开区间内,查找的范围必不包括right,所以这时候的赋值right更新为middle
class Solution(object):
def search(self, nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: int
"""
left = 0
right = len(nums)
while left < right:
middle = left + (right - left) // 2
if nums[middle] > target:
right = middle
elif nums[middle] < target:
left = middle + 1
else:
return middle
return -1
总结:当左闭右闭时,例如我们可以查找【2,2】区间,当左闭右开时,我们只能查找【2,3】区间,所以此时对于left的定义有区别,前者可以减一,后者不可。所以对于前者,middle赋值的时候可以-1.
class Solution {
public int search(int[] nums, int target) {
if (target nums[nums.length - 1]) {
return -1;
}
int left = 0, right = nums.length - 1;
while (left<=right) {
int middle = left + ((right - left)>>1); //右移一位相当于除2,右移n位相当于除以2的n次方。
if (nums[middle] < target)
left = middle + 1;
else if (nums[middle] > target)
right = middle - 1;
else if (nums[middle] == target)
return middle;
}
return -1;
}
}
class Solution {
public int search(int[] nums, int target) {
if (target nums[nums.length - 1]) {
return -1;
}
int left = 0, right = nums.length;
while (left>1); //右移一位相当于除2,右移n位相当于除以2的n次方。
if (nums[middle] < target)
left = middle + 1;
else if (nums[middle] > target)
right = middle ;
else if (nums[middle] == target)
return middle;
}
return -1;
}
}
这个题目暴力的解法就是两层for循环,一个for循环遍历数组元素 ,第二个for循环更新数组。
class Solution(object):
def removeElement(self, nums, val):
"""
:type nums: List[int]
:type val: int
:rtype: int
"""
i = 0
a = len(nums)
while i < a:
if nums[i] == val:
for j in range(i+1,a):
nums[j-1] = nums[j]
i -= 1
a -= 1
i += 1
return a
双指针法(快慢指针法): 通过一个快指针和慢指针在一个for循环下完成两个for循环的工作。
class Solution(object):
def removeElement(self, nums, val):
"""
:type nums: List[int]
:type val: int
:rtype: int
"""
a = len(nums)
fast = 0
slow = 0
while fast < a:
if nums[fast] != val:
nums[slow] = nums[fast]
slow += 1
fast += 1
return slow
注:双指针法,一个快指针判断,慢指针接收。注意思想,判断不一定是正判断,逆判断有时候效果更好。
class Solution {
public int removeElement(int[] nums, int val) {
int slow = 0;
for (int fast = 0; fast < nums.length; fast++){
if (nums[fast] != val){
nums[slow] = nums[fast];
slow++;
}
}
return slow;
}
}