算法基础——分治法和二叉查找,旋转排序数组
编辑时间:2023/9/21
1.二叉树查找
树与二叉树
树的度 节点度数最高的度数为为树的度,度为一个节点拥有的孩子节点数
叶子节点 没有孩子节点
分支节点 有相应的节点
内部节点 不是根节点和叶子节点
父节点,子节点相对的概念。
兄弟节点 平级的节点同一个父节点
树的层次 从根节点往下数从1开始
满二叉树
没有缺失的部分
完全二叉树
除了最底下一层,上面是满的,从左到右排列,缺失为右边部分。否则叫为非完全二叉树
二叉树的重要特性
在二叉树的第i层上最多拥有2的i减1个节点 i大于等于1
深度为k的二叉树最多有2的k减1个节点 k大于等于1
对于任何一颗二叉树如果其叶子结点为n0 度为2的节点数为n2 则n0=n2+1
如果对一棵有 n个结点的完全叉树的结点按层序编号、即从第1层到
2.1旋转数组问题描述
1.从下标0开始计数,在未知下标处进行旋转数组(将k和k后面的值拼接到0到k-1数组前)
2.查找旋转数组nums是否存在target值,存在返回下标,不存在返回-1
3.时间复杂度为 O(log n)
【来源力扣】https://leetcode.cn/problems/search-in-rotated-sorted-array/
2.2解题思路
二叉查找target
(1)nums.[mid]=target 直接返回nums.[mid]
(2)nums.[mid]<nums.[right] 右边界有序
(3)nums.[mid]>nums.[right] left到mid有序
在有序这段数组是否存在target
2.3算法描述
下面展示一些 JAVA
。
class Solution {
public int search(int[] nums, int target) {
int left = 0;
int len=nums.length;
int right = len- 1;
//二叉查找 target值
while (left <= right) {
int mid = (left + right) /2;
//nums.[mid]=target 直接返回nums.[mid]
if (nums[mid] == target)
return mid;
else if (nums[mid] < nums[right]) {
//nums.[mid]<nums.[right] 右边界有序 在有序这段数组是否存在target
if (nums[mid] < target && target <= nums[right])
left = mid + 1;
else
right = mid - 1;
} else {
// nums.[mid]>nums.[right] left到mid有序 在有序这段数组是否存在target
if (nums[left] <= target && target < nums[mid])
right = mid - 1;
else
left = mid + 1;
}
}
return -1;
}
}
下界代码:大于等于target第一个值
static int search(int[] nums,int t){
int left=0;
int right.nums.length-1;
while(left<right){
int mid=(right+left)/2;
if(t<=nums[mid])
right=mid;
else
left=mid+1;
}
return left;
}
上界代码:小于等于target最后一个值
static int search(int[] nums, int t) {
int left = 0;
int right = nums.length - 1;
while (left < right) {
int mid = (left + right) / 2;
if (t<a[mid])
right = mid-1;
else
left = mid ;
}
return left;
}
2.4时间复杂度和空间复杂度问题
1.对于包含重复元素的旋转排序数组,它会对程序的时间复杂度产生影响。在最坏情况下,当数组中的元素都相同时,我们无法通过比较第一个元素和最后一个元素来确定数组是否经过了旋转,因此需要逐个遍历数组来查找目标元素,时间复杂度会变为O(n)。而在其他情况下,仍然可以使用二分查找的方法来找到目标元素,时间复杂度为O(logn)。
2.通常来说,只要算法不涉及到动态分配的空间以及递归、栈所需的空间,空间复杂度通常为0(1)。其中二叉查找的空间复杂度为O(1)
3讨论与总结
解决该题,我们可以发现旋转排序数组是一个分段上升的函数,故我们可以判断分段点,将数组分段处理查找target值。