#诗经·秦风·蒹葭
蒹葭苍苍,白露为霜。所谓伊人,在水一方。溯洄从之,道阻且长。溯游从之,宛在水中央。
蒹葭凄凄,白露未晞。所谓伊人,在水之湄。溯洄从之,道阻且跻。溯游从之,宛在水中坻。
蒹葭采采,白露未已。所谓伊人,在水之涘。溯洄从之,道阻且右。溯游从之,宛在水中沚
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:
- 当target在nums中出现时,二分查找的流程不变;
- 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:
- 分治思想:将问题分解为两个不相关的子问题;
- 对于左端点,当targetnums[mid]时,若mid0 || target>nums[mid-1]说明mid为下确界,否则end=mid-1以排除连续相等段;
- 对于右端点,当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:
- 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中
- 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.展望
~~**继续加油!!! **
- 对于树结构,碰到需要优化时间的要会调用;
- 在分治,回溯中要学会用树的前序和后序来“选择”和“退出”;
- 在递归中,要会用剪枝来控制树的生长。