链表

改结构

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_;
};
posted @ 2020-09-13 11:52  xytpai  阅读(176)  评论(0编辑  收藏  举报