算法进阶__第4课(大楼轮廓问题、LRU、LFU、异或和为0的最多划分、最大搜索二叉子树、和为aim的最长子数组)

给定一个N行3列二维数组,每一行表示有一座大楼,一共有N座 大楼。 所有大楼的底部都坐落在X轴上,每一行
的三个值 (a,b,c)代表每座大楼的从(a,0)点开始,到 (b,0)点结束,高 度为c。 输入的数据可以保证a<b,且
a,b,c均为正数。大楼之 间可以有重合。 请输出整体的轮廓线。 例子:给定一个二维数组 [ [1, 3, 3], [2, 
4, 4], [5, 6, 1] ]
输出为轮廓线[ [1,2,3], [2,4,4], [5,6,1]]
//
//  main.cpp
//  AdvancedFour
//
//  Created by 吴珝君 on 2019/5/22.
//  Copyright © 2019年 闲着也是贤者. All rights reserved.
//
/*
 水平面上有 N 座大楼,每座大楼都是矩阵的形状,可以用一个三元组表示 (start, end, height),分别代
表其在x轴上的起点,终点和高度。大楼之间从远处看可能会重叠,求出 N 座大楼的外轮廓线。
 外轮廓线的表示方法为若干三元组,每个三元组包含三个数字 (start, end, height),代表这段轮廓的起始
位置,终止位置和高度。
 [[1, 3, 3], [2, 4, 4], [5, 6, 1]]
 [[1, 2, 3],[2, 4, 4],[5, 6, 1] ]
 */
#include <iostream>
#include <vector>
#include <map>
#include <algorithm>
using namespace std;

class Position{
    public:
    Position(bool isup, int x, int hight)
    {
        this->isup = isup;
        this->x = x;
        this->hight = hight;
    }
    bool isup;
    int x;
    int hight;
};

class Building{
    public:
    Building(int start, int end, int hight)
    {
        this->start = start;
        this->end = end;
        this->hight = hight;
    }
    int start;
    int  end;
    int hight;
};
bool comp(Position o1, Position o2)
{
    if (o1.x != o2.x) {
        return o1.x < o2.x;
    }
    if (o1.isup != o2.isup) {
        if (o1.isup) {
            return true;
        }
        return false;
    }
    
    return false;
}
class DealDate
{
    public:
    vector<vector<int>> getOutline(vector<Building> vb)
    {
        vector<vector<int>> res;
        map<int , int> htmap;
        map<int, int> maxmap;
        vector<Position> v = getPosition(vb);
        sort(v.begin(), v.end(), comp);
        for (int i = 0; i < v.size(); i++) {
            if(v[i].isup)
            {
                if (htmap.count(v[i].hight) == 0)
                {
                    htmap[v[i].hight] = 1;
                }
                else
                {
                    htmap[v[i].hight]++;
                }
            }
            else
            {
                if(htmap.find(v[i].hight)->second>=1)//遍历
                {
                    if (htmap.find(v[i].hight)->second == 1)
                    {
                        htmap.erase(v[i].hight);
                    }
                    else
                    {
                        htmap[v[i].hight]--;
                    }//
                }
            }
            if (htmap.empty()) {
                
                maxmap[v[i].x] =0;
            }
            else
            {
                maxmap[v[i].x] = htmap.rbegin()->first;
                
            }
            
        }
        int h =0;
        int start = 0;
        map<int, int>::iterator it ;
        for ( it = maxmap.begin(); it != maxmap.end(); it++) {
            int hcur = it->second;
            cout << hcur <<endl;
            
            if (h != hcur)
            {
                if (h !=0)
                {
                    vector<int> v;
                    v.push_back(start);
                    v.push_back(it->first);
                    v.push_back(h);
                    res.push_back(v);
                }
                start = it->first;
                h = hcur;
            }
        }
        
        return res;
    }
    
    private:
    vector<Position> getPosition(vector<Building> vb)
    {
        vector<Position> v;
        for (int i = 0; i < vb.size(); i++) {
            v.push_back(Position( true,vb[i].start,vb[i].hight));
            v.push_back(Position(false, vb[i].end,vb[i].hight));
        }
        return v;
    }
    
    
    
    
};
设计可以变更的缓存结构(LRU) 【题目】
设计一种缓存结构,该结构在构造时确定大小,假设大小为K,并有两个功能: set(key,value):将记录
(key,value)插入该结构。 get(key):返回key对应的value值。
【要求】
1.set和get方法的时间复杂度为O(1)。 2.某个key的set或get操作一旦发生,认为这个key的记录成了最经常使
用的。
3.当缓存的大小超过K时,移除最不经常使用的记录,即set或get最久远的。
【举例】
假设缓存结构的实例是cache,大小为3,并依次发生如下行为: 1.cache.set("A",1)。最经常使用的记录为
("A",1)。 2.cache.set("B",2)。最经常使用的记录为("B",2),("A",1)变为最不经常的。 
3.cache.set("C",3)。最经常使用的记录为("C",2),("A",1)还是最不经常的。 4.cache.get("A")。最经常
使用的记录为("A",1),("B",2)变为最不经常的。 5.cache.set("D",4)。大小超过了3,所以移除此时最不经
常使用的记录("B",2), 加入记录 ("D",4),并且为最经常使用的记录,然后("C",2)变为最不经常使用的 记录


typedef struct double_link_list
{
    int key;
    int val;
    struct double_link_list *pre;
    struct double_link_list *next;
    double_link_list(int key, int val)
    {
        this->key = key;
        this->val = val;
        this->pre = NULL;
        this->next = NULL;
    }
} Linklist;
class LRUCache {
public:
    /*
     * @param capacity: An integer
     */LRUCache(int capacity) {
         // do intialization if necessary
         this->capacity = capacity;
         head = NULL;
         tail = NULL;
     }
    
    /*
     * @param key: An integer
     * @return: An integer
     */
    int get(int key) {
        // write your code here
        if (umlist.count(key)) {
 
            int t = umlist.find(key)->second->val;
            set(key, t);
            return t;
        }
        else
            return -1;
    }
    
    /*
     * @param key: An integer
     * @param value: An integer
     * @return: nothing
     */
    void set(int key, int value) {
        // write your code here
        if (umlist.count(key) == 1) {
            Linklist *cur = umlist.find(key)->second;
            if (head == cur &&  (cursize >1)) {//是头节点并且当前节点数目大于1
                head = head->next;
                head->pre = NULL;
                tail->next = cur;
                cur->pre = tail ;
                tail = tail->next;
                tail->next = NULL;
            }
            else if((cur != tail )&& (head != cur))//不是头和尾
            {
                Linklist *p = cur->pre;
                Linklist *n = cur->next;
                p->next = n;
                n->pre = p;
                tail ->next = cur;
                cur->pre = tail;
                tail = tail->next;
                tail->next = NULL;
              
                
            }//如果只有一个元素或者是尾部元素
 
            cur->val =  value;
        }
        else
        {
            if (cursize == capacity)
            {
                //找到要删除的值
                umlist.erase(head->key);
                Linklist *l = head;
                head = head->next;
                delete l;
                l =NULL;
                cursize--;
            }
            
            Linklist *node = new Linklist(key,value);
            if (head == NULL)
            {
                head = node;
                tail = node;
            }
            else
            {
                tail ->next = node;
                node->pre = tail;
                tail = tail->next;
            }
            umlist.insert(pair<int, Linklist*>(key,node));
            cursize++;
            }
    }
private:
    int capacity;
    int cursize = 0;
    Linklist *head;
    Linklist *tail;
    unordered_map<int,Linklist*> umlist;//存key node
};
class Node
{
public:
    int key;
    int val;
    Node(int key, int val)
    {
        this->key = key;
        this->val = val;
        
    }
    
    
};
class LRUCache {
public:
    /*
     * @param capacity: An integer
     */LRUCache(int capacity) {
         // do intialization if necessary
         this->capacity = capacity;
     }
    
    /*
     * @param key: An integer
     * @return: An integer
     */
    int get(int key)
    {
        // write your code here
        if (umlist.count(key)) {
            int t = umlist.find(key)->second->val;
            set(key,t);
            return t;
        }
        return -1;
    }
    
    /*
     * @param key: An integer
     * @param value: An integer
     * @return: nothing
     */
    void set(int key, int value) {
        // write your code here
        if (umlist.count(key) == 1) {
            //删除当前位置节点,并增加到尾部
            Node *node = umlist.find(key)->second;
            list<Node*>::iterator it = find(l.begin(),  l.end(), node);//找到当前节点位置
            l.erase(it);
            node->val = value;
            l.push_back(node);
        }
        else
        {
            if (l.size() == capacity)
            {
                
                umlist.erase(l.front()->key);
                  l.pop_front();
            }
            Node *node = new Node(key, value);
            l.push_back(node);
            umlist.insert(pair<int,Node* >(key, node));
        }
        
        
        
    }
private:
    int capacity;
    list<Node*> l;
    unordered_map<int,Node*> umlist;//存key node
};
#include <list>
using namespace std;
class Node
{
public:
    int key;
    int val;
    Node( int key,int val)
    {
        this->key = key;
        this->val = val;
        
    }
};
class LRUCache {
public:
    /*
     * @param capacity: An integer
     */LRUCache(int capacity) {
         // do intialization if necessary
         this->capacity = capacity;
     }
    
    /*
     * @param key: An integer
     * @return: An integer
     */
    int get(int key)
    {
        // write your code here
        if (umlist.count(key)) {
            int ret = (*(umlist.find(key)->second))->val;
            set(key, ret);
            return ret;
        }
        return -1;
    }
    
    /*
     * @param key: An integer
     * @param value: An integer
     * @return: nothing
     */
    void set(int key, int value) {
        // write your code here
        if (umlist.count(key)) {
            list<Node*>::iterator it = umlist.find(key)->second;
            Node *node = *it;
            node->val = value;
            l.erase(it++);
            l.push_back(node);
            umlist[key] = (--l.end());
           // umlist.insert(pair<int, list<Node*>::iterator >(key, --l.end()));
           /*
           需要先删除再操作
           */
        }
        else
        {
            if (l.size() == capacity)
            {
                
                umlist.erase(l.front()->key);
                l.pop_front();
            }
            Node *node = new Node(key, value);
            l.push_back(node);
            //umlist.insert(pair<int, list<Node*>::iterator >(key, --l.end()));
              umlist[key] = (--l.end());
        }
    }
private:
    int capacity;
    list<Node*> l;
    unordered_map<int,list<Node*> ::iterator > umlist;//存key node
};
上一题实现了LRU缓存算法,LFU也是一个著名的缓存算法 自行了解之后实现LFU中的set 和 get 要求:两个方法
的时间复杂度都为O(1)
给定一个数组arr,和一个整数num,求在arr中,累加和等于num的最长 子数组的长度
例子:
arr = {7,3,2,1,1,7,7,7} num = 7 其中有很多的子数组累加和等于7,但是最长的子数组是{3,2,1,1},所 
以返回其长度4
/*
求和为aim值的最长子数组
*/
/*
 算法的思路,就是找到计算从第一个数组到某个子数组的和,每计算一个,就减去目标值,计算当前的结果数组中,
 有没有对应的sum,如果有的话,获取这个值得坐标位置,没有则什么都不做。
 */
class Solution
{
    public:
    vector<int> getChildArr(vector<int> arr, int aim)
    {
        vector<int> res;
  
        int sum = 0;
        map<int,int> m;//sum + 坐标
        m.insert(pair<int, int>(0, -1));//一个值也没放的时候坐标是-1 sum =0
        int start =-1;//起始下标也是-1
        int end = -1;//终止下标也是-1
        
        for (int i = 0; i < arr.size(); i++) {
            sum+=arr[i];
            if (m.count(sum -aim) ==1)
            {
               
                if(end -start <( i - m.find(sum - aim)->second))
                {
                start = m.find(sum - aim)->second;
                end = i;
                }
            }
            else
            {
            m.insert(pair<int, int>(sum, i));//只会保存最先出现的i值
            }
        }
        for (int i = start; i <end; i++) {
            res.push_back(arr[i+1]);
            
        }
        
        return res;
    }
};
定义数组的异或和的概念: 数组中所有的数异或起来,得到的结果叫做数组的异或和, 比如数组{3,2,1}的异或
和是,3^2^1 = 0
给定一个数组arr,你可以任意把arr分成很多不相容的子数组,你的目的是: 分出来的子数组中,异或和为0的子
数组最多。
请返回:分出来的子数组中,异或和为0的子数组最多是多少?
class Solution
{
    public:
    int mostEor(vector<int> arr)
    {
        if(arr.size() == 0)
        return 0;
        int xors =0;
        map<int, int> m;
        int dp[1000] = {0};
        if (arr[0] == 0)
        {
            dp[0] = 1;
        }
        m.insert(pair<int, int>(arr[0],0));
        m[xors] = arr[0];
        for (int i = 1; i < arr.size(); i++)
        {
            xors ^=arr[i];
            if (m.count(xors))//如果遇到相同的时候异或和一定是0
            {
                int l = dp[m.find(xors)->second] +1;
                int r = dp[i - 1];
                dp[i] = (l > r ? l : r);
            }
            else
            {
                dp[i] = dp[i - 1];
            }
              m[xors] = i;
        }
        return dp[arr.size()-1];
    }
};
给定一棵二叉树的头节点head,请返回最大搜索二叉子树的大小

 

//
//  main.cpp
//  maxBST
//
//  Created by 吴珝君 on 2019/5/29.
//  Copyright © 2019年 闲着也是贤者. All rights reserved.
//

#include <iostream>
#include <string.h>
class TreeNode {
public:
    int val;
    TreeNode *left, *right;
    TreeNode(int val) {
        this->val = val;
        this->left = this->right = NULL;
    }
};
class retData
{
public:
    retData(int s, TreeNode *current, int max, int min)
    {
        this->size = s;
        this->head = current;
        this->max = max;//左子树最大值节点
        this->min = min;//右子树最小值节点
    }
    int size;//返回当前所在子树的最大搜索子树节点个数
    TreeNode *head;//最大搜索二叉树的头
    int max;
    int min;//当前子树的最大值与最小值
};
#include <algorithm>
using namespace std;
class Solution
{
public:
    retData maxBST(TreeNode *root)
    {
        if(root == NULL)
        {
            
            return   retData(0,NULL,-65535,65535);//当该节点为空的时候的处理,最大值赋值为最小,最小值赋值为最大,来避免对后序比较的影响
        }
        TreeNode *left = root->left;
        TreeNode *right = root->right;
        retData l = maxBST(left);
        retData r = maxBST(right);
        int includeroot = 0;
        int maxs = 0;
        int mins = 0;
        TreeNode * curNode = NULL;
        if (l.head == left && r.head == right
            &&l.max < root->val && r.min > root->val )
        {
            includeroot = l.size + r.size + 1;
        }
        //其他情况都是在子树中找最大的
        int maxpath = max(includeroot,max( l.size, r.size));//当前子树的最大节点个数
        //求当前节点位置的最大二叉搜索子树
        curNode = (l.size > r.size ? l.head : r.head);
        if (maxpath == includeroot) {
            curNode = root;
        }//当前最大子树的根节点
        maxs = max(max(l.max,r.max),root->val);//当前子树最大节点
        mins = min(min(l.min, r.min), root->val);//当前子树最小节点
        return retData(maxpath, curNode, maxs,mins);
    }
    
    
    
};
//
void inorder(TreeNode *root)
{
    if (root == NULL) {
        return;
    }
    inorder(root->left);
    cout << root->val<<endl;
    inorder(root->right);
    
}

int main(int argc, const char * argv[]) {
    // insert code here...
    std::cout << "Hello, World!\n";
    TreeNode *r = new TreeNode(15);
    r->left = new TreeNode(14);
    r->left->left = new TreeNode (100);
    r->left->left->left = new TreeNode (90);
    r->left->left->right = new TreeNode (101);
    r->right = new TreeNode(20);
    r->right->left = new TreeNode(19);
    r->right->right = new TreeNode(21);
    Solution s;
  retData rt =    s.maxBST(r);
    inorder(rt.head);
    cout << rt.size <<endl;
    return 0;
}
给定一个数组arr,和一个整数num,求在arr中,累加和等于num的最长 子数组的长度
例子:
arr = {7,3,2,1,1,7,7,7} num = 7 其中有很多的子数组累加和等于7,但是最长的子数组是{3,2,1,1},所 以返回其长度4

求和为aim值的最长子数组
*/
/*
 算法的思路,就是找到计算从第一个数组到某个子数组的和,每计算一个,就减去目标值,计算当前的结果数组中,
 有没有对应的sum,如果有的话,获取这个值得坐标位置,没有则什么都不做。
 */
class Solution
{
    public:
    vector<int> getChildArr(vector<int> arr, int aim)
    {
        vector<int> res;
  
        int sum = 0;
        map<int,int> m;//sum + 坐标
        m.insert(pair<int, int>(0, -1));//一个值也没放的时候坐标是-1 sum =0
        int start =-1;//起始下标也是-1
        int end = -1;//终止下标也是-1
        
        for (int i = 0; i < arr.size(); i++) {
            sum+=arr[i];
            if (m.count(sum -aim) ==1)
            {
               
                if(end -start <( i - m.find(sum - aim)->second))
                {
                start = m.find(sum - aim)->second;
                end = i;
                }
            }
            else
            {
            m.insert(pair<int, int>(sum, i));//只会保存最先出现的i值
            }
        }
        for (int i = start; i <end; i++) {
            res.push_back(arr[i+1]);
            
        }
        
        return res;
    }
};

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值