leetcode---二分搜索和BST【2020第一版】

#诗经·秦风·蒹葭
蒹葭苍苍,白露为霜。所谓伊人,在水一方。溯洄从之,道阻且长。溯游从之,宛在水中央。
蒹葭凄凄,白露未晞。所谓伊人,在水之湄。溯洄从之,道阻且跻。溯游从之,宛在水中坻。
蒹葭采采,白露未已。所谓伊人,在水之涘。溯洄从之,道阻且右。溯游从之,宛在水中沚

0.二分搜索的基础

\qquad 针对有序序列建立二叉树来简化时间复杂度,从O(N)到O(lonN)。

基于递归树的实现
bool binary_search(vector<int>&sort_array,int begin,int end,int target)
{
	if(begin>end) return false;
	int mid = begin + (end-begin)/2;
	if (target==sort_array[mid])  return true;
	else if(target<sort_array[mid])
		return binary_search(sort_array,begin,mid-1,target);
	else
		return binary_search(sort_array,mid+1,end,target);
}
基于循环的实现
bool binary_search(vector<int>&sort_array,int target)
{
	int begin = 0;
	int end   = sor_array.size()-1;
	while(begin<=end)
	{
		int mid = begin + (end-begin)/2;
	if (target==sort_array[mid]) return true;
	else if(target<sort_array[mid])
		end = mid-1;
	else
		begin = mid+1;
	}
	return false;
}

1.二分搜索加限制条件

1.1 插入位置

在这里插入图片描述
A:

  1. 当target在nums中出现时,二分查找的流程不变;
  2. target在nums中没有出现时:
  • target<nums[mid] && target>nums[mid-1] (注意mid=0的边界条件);
  • targer>nums[mid] && target<num[mid+1] (注意mid=size-1的边界条件);
int searchInsert(vector<int>&nums,int target)
{
	int begin = 0;
	int end = nums.size()-1;
	int index = -1; //使用-1作为循环进入条件,为-1说明一直没找到
	while(index == -1):
	{
		int mid = begin + (end-begin)/2;
		if(nums[mid]==target)
		{
			index = mid;
		}
		else if(target<nums[mid])
		{
			if(mid==0 || target>nums[mid-1])  //与mid前一个元素作比较
				index = mid;
			end = mid-1;
		}
		else //target>nums[mid]
		{
			if(mid==nums.size() || target<nums[mid+1]) //与mid后一个元素作比较
				index = mid+1;
			begin = mid + 1;
		}
	}
	return index;
}

1.2 区间查找

在这里插入图片描述
A:

  1. 分治思想:将问题分解为两个不相关的子问题
  2. 对于左端点,当targetnums[mid]时,若mid0 || target>nums[mid-1]说明mid为下确界,否则end=mid-1以排除连续相等段;
  3. 对于右端点,当target=nums[mid]时,若mid==size-1 || target<nums[mid+1],说明mid为上确界,否则begin=mid+1以排除连续相等段;
int left_bound(vector<int>&nums,int target)
{
	int begin = 0;
	int end = nums.size();
	while(begin<=end)
	{
		int mid = begin + (end - begin)/2;
		if(target==nums[mid])
		{
			if(mid==0 || target>nums[mid-1])
				return mid;
			else
				end = mid-1;
		}
		else if(target<nums[mid])
			end = mid-1;
		else //target>nums[mid]
			begin = mid+1;
	}
}
int right_bound(vector<int>&nums, int target)
{
int begin = 0;
	int end = nums.size();
	while(begin<=end)
	{
		int mid = begin + (end - begin)/2;
		if(target==nums[mid])
		{
			if(mid==nums.size() || target<nums[mid+1])
				return mid+1;
			else
				begin = mid+1;
		}
		else if(target<nums[mid])
			end = mid-1;
		else //target>nums[mid]
			begin = mid+1;
	}	
}

1.3 旋转数组查找

在这里插入图片描述
A:

  1. target<nums[mid]
  • nums[begin]<nums[mid] 说明前半段为有序序列
    –target>=nums[begin] 就在前半段找
    –target<nums[begin] 只能去后半段找
  • nums[begin]>nums[mid] 说明后半段为有序序列
    ----只能去前半段找
    -nums[begin] == nums[mid] 【6,1】中找1
    –target在mid+1,end中
  1. target>nums[mid]
  • nums[begin]<nums[mid] 说明前半段为有序序列
    ----只能去后半段找
  • nums[begin]>nums[mid] 说明后半段为有序序列
    –target>=nums[begin] 就在前半段找
    –target<nums[begin] 只能去后半段找
    -nums[begin] == nums[mid] 【6,7】中找7
    –target在mid+1,end中
int segement_search(vector<int>& nums,int target)
{
	int begin = 0;
	int end = nums.size()-1;
	while(begin<=end)
	{
		int mid = begin + (end-begin)/2;
		if(target == nums[mid])
			return mid;
		else if(target<nums[mid])]
		{
			if(nums[begin]==nums[mid])
				begin = mid+1;
			else if(nums[begin]<nums[mid]) //前半段有序
			{
				if(target>=nums[begin])
					end = mid-1;
				else
					begin = mid+1;
			}
			else if(nums[begin]>nums[mid])
				end = mid-1;
		}	
		else if(target>nums[mid])]
		{
			if(nums[begin]==nums[mid])
				begin = mid+1;
			else if(nums[begin]>nums[mid]) //后半段有序
			{
				if(target>=nums[begin])
					end = mid-1;
				else
					begin = mid+1;
			}
			else if(nums[begin]<nums[mid])
				begin = mid+1;
		}	
	
	}

}

2. 二叉查找(排序)树

\quad 二叉排序树的**“增”**

void BST_insert(TreeNode* node, TreeNode* insert_node)
{
	if(insert_node->val < node->val)
	{
		if(node->left)
			BST_insert(node->left,insert_node);
		else 
			node->left = insert_node;			
	}
	else if(insert_node->val > node->val)
	{
		if(node->right)
			BST_insert(node->right,insert_node);
		else
			node->right = insert_node;
	}
	//仅考虑树上节点各部相同的情形
}

\quad 二叉排序树的“查”

bool BST_search(TreeNode* node, int search)
{
	if(node->val == search)
		return true;
	else if(node->val > search)
	{
		if(node->left)
			return BST_search(node->left,search);
		else
			return false;
	}
	else//(node->val < search)
	{
		if(node->right)
			return BST_search(node->right,search);
		else 
			return false;
		//node->right? return BST_search(node->rigth,search): return false;
	}
}

2.1 逆序数改造树

在这里插入图片描述

struct BSTNode
{
    int val;
    int count;
    BSTNode* left;
    BSTNode* right;
    BSTNode(int x): val(x),left(NULL),right(NULL),count(0){}
};
class Solution {
public:
    vector<int> countSmaller(vector<int>& nums)
    {
        vector<int> result;
        vector<BSTNode*> node_vec;
        vector<int> count;
        for(int i=nums.size()-1;i>=0;--i)
        {
            node_vec.push_back(new BSTNode(nums[i]));
        }
        count.push_back(0);
        for(int i=1; i<node_vec.size();++i)
        {
            int count_small = 0;
            BSTinsert(node_vec[0],node_vec[i],count_small);
            count.push_back(count_small);
        }
        for(int i=node_vec.size()-1;i>=0;--i)
        {
            delete node_vec[i];
            result.push_back(count[i]);
        }
        return result;

    }
private:
    void BSTinsert(BSTNode* node, BSTNode* insert_node, int& count_small)
    {
        if(insert_node->val <= node->val)
        {
            ++node->count;
            if(node->left)
            {
                BSTinsert(node->left,insert_node,count_small);
            }
            else
                node->left = insert_node;
        }
        else
        {
            count_small += (node->count + 1);
            if(node->right)
                BSTinsert(node->right,insert_node,count_small);
            else 
                node->right = insert_node;
        }
    }
};

3.展望

在这里插入图片描述
~~**继续加油!!! **

  • 对于树结构,碰到需要优化时间的要会调用;
  • 在分治,回溯中要学会用树的前序和后序来“选择”和“退出”;
  • 在递归中,要会用剪枝来控制树的生长。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值