《面试算法 LeetCode 刷题班》——6.二叉查找与二叉查找树

本文内容是基于小象学院——林沐 《面试算法 LeetCode 刷题班》,后期仍将对相关内容进行不定期更新!

6.二叉查找与二叉查找树

  1. 二分查找的递归实现

    bool binary_search(vector &sort_array, int begin, int end, int target) {
    if (begin > end)
    {
    return false;
    }

     int mid = (end + begin) / 2;
     if (sort_array[mid] == target)
     {
     	return true;
     }
     else if (sort_array[mid] > target)
     {
     	return binary_search(sort_array, begin, mid-11, target);
     }
     else if (sort_array[mid] < target)
     {
     	return binary_search(sort_array, mid+1, end, target);
     }
    

    }

LeetCode 35 插入位置

需要考虑的情况

《面试算法 LeetCode 刷题班》——6.二叉查找与二叉查找树

代码:

class Solution {
public:
	int searchInsert(vector<int>& nums, int target) {
		int index = -1;
		int begin = 0;
		int end = nums.size();
		while (index == -1)
		{
			int mid = (begin + end) / 2;
			if (target == nums[mid])
			{
				return mid;
			}
			else if (target < nums[mid]) {
				if (mid == 0 || target > nums[mid-1])
				{
					index = mid;
				}
				end = mid - 1; // 更新右端点值
			}
			else if (target > nums[mid]) {
				if ( mid == nums.size()-1 || target < nums[mid + 1])
				{
					index = mid + 1;
				}
				begin = mid + 1; // 更新左端点值
			}
		}
		return index;
	}
};

LeetCode 34 查找区间

思路: 通过二分法找寻左端点和右端点。

代码:

class Solution {
public:
	vector<int> searchRange(vector<int>& nums, int target) {
		vector<int> result;
		result.push_back(left_bound(nums, target));
		result.push_back(right_bound(nums, target));
		return result;
	}

	int left_bound(vector<int>& nums, int target) {
		int begin = 0;
		int end = nums.size() - 1;
		while (begin <= end)
		{
			int mid = (begin + end) / 2;
			if (target == nums[mid])
			{
				if (mid == 0 || nums[mid - 1] < target) {
					return mid;
				}
				end = mid - 1;
			}
			else if (target > nums[mid])
			{
				begin = mid + 1;
			}
			else if (target < nums[mid])
			{
				end = mid - 1;
			}
		}
		return -1;
	}

	int right_bound(vector<int>& nums, int target) {
		int begin = 0;
		int end = nums.size() - 1;
		while (begin <= end)
		{
			int mid = (begin + end) / 2;
			if (target == nums[mid])
			{
				if (mid == nums.size() - 1 || nums[mid + 1] > target) {
					return mid;
				}
				begin = mid + 1;
			}
			else if (target > nums[mid])
			{
				begin = mid + 1;
			}
			else if (target < nums[mid])
			{
				end = mid - 1;
			}
		}
		return -1;
	}
};

LeetCode 33 旋转数组查找

本题目主要是观察旋转数组的特性,当数组发生旋转时,数组头元素是大于尾元素的。所以需要判断数组是否属于旋转区间。
逻辑关系还是要理理清楚!

class Solution {
public:
	int search(vector<int>& nums, int target) {
		int begin = 0;
		int end = nums.size() - 1;
		while (begin <=end)
		{
			int mid = (begin + end) / 2;
			if (nums[mid] == target)
			{
				return mid;
			}
			else if (target < nums[mid]) {
				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 (nums[begin] == nums[mid]) {
					begin= mid + 1;
				}
			}
			else if (target > nums[mid])
			{
				if (nums[begin] > nums[mid])
				{
					if (target < nums[begin])
					{
						begin = mid + 1;
					}
					else
					{
						end = mid - 1;
					}
					
				}else if (nums[begin] < nums[mid]){
					begin = mid + 1;
				}
				else if (nums[begin] == nums[mid])
				{
					begin =  mid + 1;
				}
			}
		}
		return -1;
	}
};

LeetCode 449

预备知识:

二叉查找树:

  1. 若左子树不空,则左子树上所有节点的值均小于或等于它的根节点的值
  2. 若右子树不空,则右子树上所有节点的值均大于或等于它的根节点的值
  3. 左、右字树也分别是二叉排序树
  4. 等于的情况只能出现在左或者右子树的某一侧

插入算法:

将节点insert_node 插入到以 node 为根的二叉查找树中,如果insert_node节点值小于当前node 值,若node有左子树,则递归的将该节点插入至左子树为根的二叉排序树种,否则node->left 赋值为该节点地址。否则 node 有右子树,则递归的将该节点插入至右子树为根二叉排序树中,否则,将node->right赋值为该节点地址。

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 (node->right)
		{
			BST_insert(node->right, insert_node);
		}
		else {
			node->right = insert_node;
		}
	}
}

查找数值:

查找数值 value 如果数值等于当前节点则返回真,若小于则在左子树中查找否则返回假;若大于则在右子树中找否则返回假。

bool BST_search(TreeNode *node, int value) {
	if (node->val == value)
	{
		return true;
	}
	if (node->val > value) {
		if (node->left) {
			 return BST_search(node->left, value);
		}
		else { // 要考虑左子树不为空
			return false;
		}
	}
	else {
		if (node->right)
		{
			return BST_search(node->right, value);
		}
		else {
			return false;
		}
	}
}

思路:?

代码:

class Codec {
public:

void change_int_to_string(int val, string &str_val) {
	string tmp;
	while (val)
	{
		tmp += val % 10 + '0';
		val = val / 10;
	}
	for (int i = tmp.length()-1; i >= 0; i--)
	{
		str_val += tmp[i];
	}
	str_val += '#';
}

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 (node->right)
		{
			BST_insert(node->right, insert_node);
		}
		else {
			node->right = insert_node;
		}
	}
}

void BST_preorder(TreeNode *node, string &data) {
	if (!node)
	{
		return;
	}
	string str_val;
	change_int_to_string(node->val, str_val);
	data += str_val;
	BST_preorder(node->left, data);
	BST_preorder(node->right, data);
}
	// Encodes a tree to a single string.
	string serialize(TreeNode* root) {
		string data;
		BST_preorder(root, data);
		return data;
	}

	// Decodes your encoded data to tree.
	TreeNode* deserialize(string data) {
		if (data.length() == 0)
		{
			return NULL;
		}
		vector<TreeNode *> node_vec;
		int val = 0;
		for (int i = 0; i < data.length(); i++) {
			if (data[i] == '#')
			{
				node_vec.push_back(new TreeNode(val));
				val = 0;
			}
			else
			{
				val = val * 10 + data[i] - '0';
			}
		}
		for (int i = 1; i < node_vec.size(); i++) {
			BST_insert(node_vec[0], node_vec[i]);
		}
		return node_vec[0];
	}
};

LeetCode 315 逆序数 (解法2)

将给的数组中的元素逆序,再分别加入到二叉查找树中,只要查找到目标数值在的节点的左子树下的元素个数就是逆序数的个数,再将得到的数组返回就是结果了。

struct  BSTNode
{
	int val;
	int count;
	BSTNode *left;
	BSTNode *right;
	BSTNode(int x) : val(x),left(NULL), right(NULL),count(0) {}
};
class Solution {
public:

	void BST_search(BSTNode *node, BSTNode *insert_node, int &count_small) {
		if (insert_node->val <= node->val)
		{
			node->count++;
			if (node->left)
			{
				BST_search(node->left, insert_node, count_small);
			}
			else {
				node->left = insert_node;
			}
		}
		else {
			count_small += node->count + 1;
			if (node->right)
			{
				BST_search(node->right, insert_node, count_small);
			}
			else {
				node->right = insert_node;
			}
		}
	}
	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;
			BST_search(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]);
		} // count_small 数组按照从后往前 push 进入 result数组
		return result;
	}
};