本文内容是基于小象学院——林沐 《面试算法 LeetCode 刷题班》,后期仍将对相关内容进行不定期更新!
二分查找的递归实现
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-1, target);
}
else if (sort_array[mid] < target)
{
return binary_search(sort_array, mid+1, end, target);
}
}
需要考虑的情况
代码:
class Solution {
public:
int searchInsert(vector& 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;
}
};
思路: 通过二分法找寻左端点和右端点。
代码:
class Solution {
public:
vector searchRange(vector& nums, int target) {
vector result;
result.push_back(left_bound(nums, target));
result.push_back(right_bound(nums, target));
return result;
}
int left_bound(vector& 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& 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;
}
};
本题目主要是观察旋转数组的特性,当数组发生旋转时,数组头元素是大于尾元素的。所以需要判断数组是否属于旋转区间。
逻辑关系还是要理理清楚!
class Solution {
public:
int search(vector& 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;
}
};
预备知识:
二叉查找树:
插入算法:
将节点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 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];
}
};
将给的数组中的元素逆序,再分别加入到二叉查找树中,只要查找到目标数值在的节点的左子树下的元素个数就是逆序数的个数,再将得到的数组返回就是结果了。
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 countSmaller(vector &nums) {
vector result;
vector node_vec;
vector 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;
}
};