您的位置:首页 > Web前端 > Node.js

Binary search (4) -- Find Right Interval,Count Complete Tree Nodes,Divide Two Integers

2017-01-18 15:12 507 查看
Find Right Interval

Given a set of intervals, for each of the interval i, check if there exists an interval j whose start point is bigger than or equal to the end point of the interval i, which can be called that j is on the "right" of i.

For any interval i, you need to store the minimum interval j's index, which means that the interval j has the minimum start point to build the "right" relationship for interval i. If the interval j doesn't exist, store -1 for the interval i. Finally, you need
output the stored value of each interval as an array.

Note:

You may assume the interval's end point is always bigger than its start point.
You may assume none of these intervals have the same start point.

Example 1:

Input: [ [1,2] ]

Output: [-1]

Explanation: There is only one interval in the collection, so it outputs -1.

1. map: map内部实现了一个红黑树,该结构具有自动排序的功能,因此map内部的所有元素都是有序的,红黑树的每一个节点都代表着map的一个元素,因此,对于map进行的查找,删除,添加等一系列的操作都相当于是对红黑树进行这样的操作,故红黑树的效率决定了map的效率。

2. unordered_map: unordered_map内部实现了一个哈希表,因此其元素的排列顺序是杂乱的,无序的

3. 因为map是有序的,所以有lower_bound这种函数

vector<int> findRightInterval(vector<Interval>& intervals) {
vector<int> rst;
map<int, int> index_map;
for(int i = 0; i < intervals.size(); i++){
int start = intervals[i].start;
index_map[start] = i;
}

for(Interval in : intervals){
auto it = index_map.lower_bound(in.end);
if (it != index_map.end()) rst.push_back(it->second);
else rst.push_back(-1);
}
return rst;
}


Count Complete Tree Nodes

Given a complete binary tree, count the number of nodes.

Definition of a complete binary tree from Wikipedia:

In a complete binary tree every level, except possibly the last, is completely filled, and all nodes in the last level are as far left as possible. It can have between 1 and 2h nodes
inclusive at the last level h.
1. 完全二叉树:只有最下面的两层结点度能够小于2,并且最下面一层的结点都集中在该层最左边的若干位置的二叉树
2. 比较二叉树最左和最右深度,如果相等则为满二叉树,结点数为 2 ^ h - 1;如果不相等则需继续查找

3. countLeft和countRight是为了避免对子树深度的重复计算

4. 开始的想法是,先计算树的最大深度H,然后从右开始计算,相比满二叉树而言缺失的叶子结点,最后用2 ^ H - 1 - missCount。但是最后超时了,感觉原因是 遍历去寻找缺失的叶子太耗时了。就好比遍历与二分查找之间的区别。在极端情况下,二叉树最后一层只有一个结点。这种方式相当于把整棵树遍历了一遍;而比较深度的做法可以很快的计算右半部分满二叉树的结点数。

int countLeft(TreeNode* root, int hl){   //代表父结点为左儿子
if (root == NULL) return 0;
TreeNode* r = root;
int hr = 1;
while(r->right != NULL){   //计算右子树深度
r = r->right;
hr++;
}
if (hl == hr) return pow(2, hl) - 1; //该子树为满二叉树
return 1 + countLeft(root->left, hl-1) + countNodes(root->right);   //左子树的深度无需重复计算,只需计算右子树深度
}

int countRight(TreeNode* root, int hr){
if (root == NULL) return 0;
TreeNode* r = root;
int hl = 1;
while(r->left != NULL){
r = r->left;
hl++;
}
if (hl == hr) return pow(2, hl) - 1;
return 1 + countNodes(root->left) + countRight(root->right, hr-1);
}

int countNodes(TreeNode* root) {
if (root == NULL) return 0;
TreeNode* r = root;
int hl = 1, hr = 1;
while(r->left != NULL){
r = r->left;
hl++;
}
r = root;
while(r->right != NULL){
r = r->right;
hr++;
}
if (hl == hr) return pow(2, hl) - 1;
return 1 + countLeft(root->left, hl-1) + countRight(root->right, hr-1);
}


Divide Two Integers

Divide two integers without using multiplication,
division and mod operator.

If it is overflow, return MAX_INT.

1. dividend = divisor * quotient + quota。除法即找dividend减去最多几个divisor仍然是大于等于0的。

2. 使用移位操作代替乘除运算符

3. 有点divide and conquer的思想。先处理一部分,再处理另一部分,然后综合几部分的结果。

int divide(int dividend, int divisor) {
if (!divisor || (dividend == INT_MIN && divisor == -1))
return INT_MAX;
int sign = (dividend < 0) ^ (divisor < 0) ? 0 : 1;  //0为负,1为正
long did = labs(dividend);  //返回long型的绝对值
long dis= labs(divisor);

int quotient = 0;
while (did >= dis){
long tmp = dis, multi = 1;
while (did >= (tmp << 1)){  //之所以要用long,是因为did为INT_MAX时,tmp << 1会越界形成死循环
tmp <<= 1;
multi <<= 1;
}
did -= tmp;
quotient += multi;
}
return sign ? quotient : -quotient;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  leetcode