zoukankan      html  css  js  c++  java
  • 链表

    改结构

    1. 反转单链表

    //用大小为三个节点的滑动窗口顺序扫描改指针
    ListNode* reverseList(ListNode *head) {
        ListNode *prev=NULL, *curr=head, *next;
        while(curr!=NULL) { //扫描, 次数一共为要转的节点数
            next = curr->next;
            curr->next = prev;
            prev = curr;
            curr = next;
        }
        return prev;
    }
    
    # 以下为递归解法, 因为递归天然记住当前节点, 所以仅仅改下指针即可
    def reverseList(self, head):
        if head == None or head.next == None:
            return head
        node = self.reverseList(head.next)
        head.next.next = head
        head.next = None # 需要这一步
        return node
    

    2. 在第m和n闭区间内反转单链表

    ListNode* reverseBetween(ListNode *head, int m, int n) {
        ListNode *prev_head=new ListNode(0); prev_head->next=head; //构建超头
        ListNode *prev_left=prev_head, *next_right=head;
        for(int i=1; i<m; i++) prev_left=prev_left->next; //左前驱
        for(int i=0; i<n; i++) next_right=next_right->next; //右后驱
        //套用一般反转链表代码
        ListNode *prev=next_right, *curr=prev_left->next, *next;
        for(int i=m; i<=n; i++) { //这里次数为要转的节点数
            next = curr->next;
            curr->next = prev;
            prev = curr;
            curr = next;
        }
        //前面接起来
        prev_left->next = prev;
        return prev_head->next;
    }
    

    3. K组反转单链表

    1->2->3->4->5
    当 k = 2 时,应当返回: 2->1->4->3->5
    当 k = 3 时,应当返回: 3->2->1->4->5
    
    ListNode* reverseKGroup(ListNode* head, int k) {
        int len = 0;
        for(ListNode *p=head; p!=NULL; p=p->next) len++;
        for(int i=0; i<len/k; i++)
            head = reverseBetween(head, i*k+1, (i+1)*k);
        return head;
    }
    

    4. 旋转单链表

    输入: 1->2->3->4->5->NULL, k = 2
    输出: 4->5->1->2->3->NULL
    
    ListNode* rotateRight(ListNode* head, int k) {
        int len=0;
        for(ListNode *p=head; p!=NULL; p=p->next) len++;
        k = len!=0 ? k % len : 0;
        if (k==0) return head;
        ListNode *slow=head, *fast=head;
        while(k--) fast = fast->next;
        while(fast->next!=NULL) { // 找两前驱
            fast = fast->next;
            slow = slow->next;
        }
        ListNode *new_head = slow->next;
        slow->next = NULL;
        fast->next = head;
        return new_head;
    }
    

    5. 奇偶链表

    给定一个单链表,把所有的奇数节点和偶数节点分别排在一起。
    请注意,这里的奇数节点和偶数节点指的是节点编号的奇偶性,而不是节点的值的奇偶性。
    输入: 1->2->3->4->5->NULL
    输出: 1->3->5->2->4->NULL
    
    ListNode* oddEvenList(ListNode* head) {
        if(head==NULL) return NULL;
        ListNode *odd=head, *even=head->next; // 双指针
        ListNode *head_odd=odd, *head_even=even;
        while(even!=NULL&&even->next!=NULL) {
            odd->next = odd->next->next;
            even->next = even->next->next;
            odd = odd->next;
            even = even->next;
        }
        odd->next = head_even;
        return head_odd;
    }
    

    6. 二路有序链表归并

    ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
        ListNode pi; // 超头
        ListNode *p1=l1, *p2=l2, *p=&pi;
        while(p1 != nullptr && p2 != nullptr) {
            if(p1->val < p2->val) {
                p->next = p1;
                p1 = p1->next;
            }
            else {
                p->next = p2;
                p2 = p2->next;
            }
            p = p->next;
        }
        p->next = p1!=nullptr?p1:p2; //剩余接起来
        return pi.next;
    }
    

    7. 链表归并排序

    ListNode* sortList(ListNode* head) {
        // 注意跳出条件与数组归并不一样
        if (head==NULL||head->next==NULL) return head;
        // 从中间拆表
        ListNode *slow=head, *fast=head, *pre;
        while(fast!=NULL&&fast->next!=NULL) {
            pre = slow;
            slow = slow->next;
            fast = fast->next->next;
        }
        pre->next = NULL;
        // 归并排序
        ListNode *l1 = sortList(head);
        ListNode *l2 = sortList(slow);
        return mergeTwoLists(l1, l2);
    }
    

    8. 链表去重

    ListNode* removeDuplicateNodes(ListNode* head) {
        head = sortList(head);
        for(ListNode *p=head; p!=NULL; ) {
            while(p->next&&(p->next->val==p->val)) {
                ListNode *temp = p->next;
                p->next = temp->next;
                delete temp;
            }
            p = p->next;
        }
        return head;
    }
    

    递归

    1. 从尾到头打印链表

    class Solution {
    public:
        vector<int> reversePrint(ListNode* head) {
            vector<int> res;
            traceback(head,res);
            return res;
        }
        void traceback(ListNode* head, vector<int> &trace) {
            if(head==NULL) return;
            traceback(head->next, trace);
            trace.push_back(head->val);
        }
    };
    

    2. 复杂链表复制

    class Solution {
    public:
        unordered_map<Node*, Node*> map;
        Node* copyRandomList(Node* head) {
            if(head==NULL) return NULL;
            if(map.count(head)) return map[head];
            Node *node = new Node(head->val);
            map[head] = node;
            node->next = copyRandomList(head->next);
            node->random = copyRandomList(head->random);
            return node;
        }
    };
    

    检测

    1. 环路检测

    ListNode *detectCycle(ListNode *head) {
        ListNode *slow=head, *fast=head;
        while(fast!=NULL && fast->next!=NULL) {
            slow = slow->next;
            fast = fast->next->next;
            if(slow==fast) { // 存在环
                fast = head; //快指针到最前面
                while(slow!=fast) { //找第一个相遇点
                    slow = slow->next; //协同步进
                    fast = fast->next;
                }
                return slow;
            }
        }
        return NULL;
    }
    

    2. 找到倒数k个节点的值

    int kthToLast(ListNode* head, int k) {
        ListNode *slow=head, *fast=head;
        while(k--) fast = fast->next;
        while(fast!=NULL) {
            slow = slow->next;
            fast = fast->next;
        }
        return slow->val;
    }
    

    LRU缓存机制实现

    /** LRUCache(int capacity) 以正整数作为容量 capacity 初始化 LRU 缓存
     * int get(int key) 如果关键字 key 存在于缓存中,则返回关键字的值否则返回-1
     * void put(int key, int value) 如果关键字已经存在,
     * 则变更其数据值;如果关键字不存在,则插入该组「关键字-值」。
     * 当缓存容量达到上限时,它应该在写入新数据之前删除最久未使用的数据值,
     * 从而为新的数据值留出空间。*/
    class LRUCache {
    public:
        LRUCache(int capacity) {
            cap_ = capacity;
            num_items_ = 0;
        }
        
        int get(int key) {
            if(map_.count(key)) {
                auto it = map_[key];
                pair<int, int> item = *it;
                lru_.erase(it);
                lru_.push_front(item);
                map_[key] = lru_.begin();
                return item.second;
            }
            else return -1;
        }
        
        void put(int key, int value) {
            if(map_.count(key)) {
                auto it = map_[key];
                pair<int, int> item = *it;
                item.second = value;
                lru_.erase(it);
                lru_.push_front(item);
                map_[key] = lru_.begin();
            }
            else {
                num_items_++;
                if(num_items_>cap_) {
                    map_.erase(lru_.back().first);
                    lru_.pop_back();
                    num_items_ = cap_;
                }
                lru_.push_front(pair<int, int>(key, value));
                map_[key] = lru_.begin();
            }
        }
    private:
        list<pair<int, int>> lru_;
        unordered_map<int, list<pair<int, int>>::iterator> map_;
        int cap_, num_items_;
    };
    
  • 相关阅读:
    【Redis破障之路】四:Jedis基本使用
    【JVM进阶之路】十二:字节码指令
    Java学习之Spring MVC路由映射
    Java安全之FastJson JdbcRowSetImpl 链分析
    Allatori混淆动态调试分析
    Java工具开发手记
    Java安全之JBoss反序列化漏洞分析
    docker 应用篇————swarm[二十]
    docker 应用篇————docker-compose[十九]
    docker 应用篇————docker 自定义网络[十八]
  • 原文地址:https://www.cnblogs.com/xytpai/p/13660829.html
Copyright © 2011-2022 走看看