C++

数据结构与算法

二分查找、二叉排序树

Posted by Bob on September 15, 2019

以下题目均来自leetcode、poj

二分查找

首先,假设表中元素是按升序排列(也可是降序),将表中间位置记录的关键字与查找关键字比较,如果两者相等,则查找成功;否则利用中间位置记录将表分成前、后两个子表,如果中间位置记录的关键字大于查找关键字,则进一步查找前一子表,否则进一步查找后一子表。重复以上过程,直到找到满足条件的记录,使查找成功,或直到子表不存在为止,此时查找不成功。


//二分查找递归

bool binary_search(std::vector<int> &sort_array,
int begin,int end,int target){
    if(begin > end){
        return false;
    }
    int mid = (begin+end)/2;
    if(target == sort_arry[mid]){
        return true;
    }else if(target < sort_arry[mid]){
        return binary_search(sort_array,begin,mid-1,target);
    }else if(target > sort_arry[mid])){
        return binary_search(sort_array,mid+1,end,target);
    }
}

//二分查找循环

bool binary_search(std::vector<int> &sort_array,int target){
    int begin = 0;
    int end = sort_array.size() - 1;
    while(begin <= end){
        int mid = (begin+end)/2;
        if(target == sort_arry[mid]){
            return true;
        }else if(target < sort_arry[mid]){
            end = mid -1;
        }else if(target > sort_arry[mid])){
            begin = mid + 1;
        }
    }
    return false;
}

搜索插入位置

给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。

你可以假设数组中无重复元素。

示例 1:

输入: [1,3,5,6], 5 输出: 2 示例 2:

输入: [1,3,5,6], 2 输出: 1 示例 3:

输入: [1,3,5,6], 7 输出: 4 示例 4:

输入: [1,3,5,6], 0 输出: 0


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



在排序数组中查找元素的第一个和最后一个位置

给定一个按照升序排列的整数数组 nums,和一个目标值 target。找出给定目标值在数组中的开始位置和结束位置。

你的算法时间复杂度必须是 O(log n) 级别。

如果数组中不存在目标值,返回 [-1, -1]。

示例 1:

输入: nums = [5,7,7,8,8,10], target = 8 输出: [3,4] 示例 2:

输入: nums = [5,7,7,8,8,10], target = 6 输出: [-1,-1]


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

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

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


搜索旋转排序数组

假设按照升序排序的数组在预先未知的某个点上进行了旋转。

( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] )。

搜索一个给定的目标值,如果数组中存在这个目标值,则返回它的索引,否则返回 -1 。

你可以假设数组中不存在重复的元素。

你的算法时间复杂度必须是 O(log n) 级别。

示例 1:

输入: nums = [4,5,6,7,0,1,2], target = 0 输出: 4 示例 2:

输入: nums = [4,5,6,7,0,1,2], target = 3 输出: -1


//部分有序,部分无序

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(target == nums[mid]){
                return mid;
            }else if(mums[mid] < mums[end] ){//如果中间的数小于最右边的数,则右半段是有序的
                //保留有序部分去找

               if(nums[mid] < target && target <= nums[end]){
                   begin = mid + 1;
               }else{
                   end = mid - 1;
               }
            }else if(mums[mid] > mums[end]){//若中间数大于最右边数,则左半段是有序的

                if(nums[begin] <= target && target < nums[mid]){
                    end = mid - 1;
                }else{
                    begin = mid + 1;
                }
            }
        }
        return -1;
    }
};


二叉排序树

二叉排序树或者是一棵空树,或者是具有下列性质的二叉树:

(1)若左子树不空,则左子树上所有节点的值均小于它的根节点的值;

(2)若右子树不空,则右子树上所有节点的值均大于它的根节点的值;

(3)左、右子树也分别为二叉排序树;

(4)没有键值相等的节点。

二叉查找树的中序遍历是从小到大的。


void BST_insert(TreeNode* node,TreeNode* insertNode){
    if(indertNode->val < node->val){
        if(node->left){
            BST_insert(node->left,insertNode);
        }else{
            node->left = indertNode->val;
        }
    }else{
        if(node->right){
            BST_insert(node->right,insertNode);
        }else{
            node->right = insertNode->val;
        }
    }
}

void BST_search(TreeNode* node,int value){
    if(value == node->val){
        return true;
    }
    if(value < node->val){
        if(node->left){
            return BST_insert(node->left,value);
        }else{
            return false;
        }
    }else{
        if(node->right){
            return BST_insert(node->right,value);
        }else{
            return false;
        }
    }
}

Serialize and Deserialize BST

Serialization is the process of converting a data structure or object into a sequence of bits so that it can be stored in a file or memory buffer, or transmitted across a network connection link to be reconstructed later in the same or another computer environment.

Design an algorithm to serialize and deserialize a binary search tree. There is no restriction on how your serialization/deserialization algorithm should work. You just need to ensure that a binary search tree can be serialized to a string and this string can be deserialized to the original tree structure.

The encoded string should be as compact as possible.


/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */

//前序

class Codec {
public:

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

    void BST_preorder(TreeNode *node,std::string &data){
        if(!node){
            return;
        }
        std::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) {
        std::string data;
        BST_preorder(root,data);
        return data;
    }

    // Decodes your encoded data to tree.
    TreeNode* deserialize(string data) {
        if(data.length() == 0){
            return NULL;
        }
        std: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];
    }
};

// Your Codec object will be instantiated and called as such:
// Codec codec;
// codec.deserialize(codec.serialize(root));


计算右侧小于当前元素的个数

给定一个整数数组 nums,按要求返回一个新数组 counts。数组 counts 有该性质: counts[i] 的值是  nums[i] 右侧小于 nums[i] 的元素的数量。

示例:

输入: [5,2,6,1] 输出: [2,1,1,0] 解释: 5 的右侧有 2 个更小的元素 (2 和 1). 2 的右侧仅有 1 个更小的元素 (1). 6 的右侧有 1 个更小的元素 (1). 1 的右侧有 0 个更小的元素.


//反序后,求前面有多少个比target小

 struct TreeNode {
      int val;
      int count;
      TreeNode *left;
      TreeNode *right;
      TreeNode(int x) : val(x), left(NULL), right(NULL),count(0) {}
  };

class Solution {
public:

    void BST_insert(TreeNode* node,TreeNode* insertNode,int &countSmall){
    if(indertNode->val < node->val){
        node->count++;
        if(node->left){
            BST_insert(node->left,insertNode,countSmall);
        }else{
            node->left = indertNode->val;
        }
    }else{
        countSmall+=node->count+1;
        if(node->right){
            BST_insert(node->right,insertNode,countSmall);
        }else{
            node->right = insertNode->val;
        }
    }


    vector<int> countSmaller(vector<int>& nums) {
        std::vector<int> result;
        std::vector<TreeNode*> node_vec;
        std::vector<int> count;
        for(int i = nums.size() -1;i >= 0;i--){
            node_vec.push_back(new TreeNode(nums[i]));
        }
        count.push_back(0);
        for(int i = 1;i < node_vec.size();i++){
            int count_small = 0;
            BST_insert(node_vec[0],node_vec[1],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;
    }
};