zoukankan      html  css  js  c++  java
  • 链表

    常用的链表结构

    • 单链表
      单链表
    • 双向链表 空间换时间
      双向链表
    • 循环链表
      循环链表
      链表的删除/插入是O(1)级别的,但是随机访问需要O(n)的复杂度
    • 双向循环链表
      双向循环链表

    技巧

    • 理解指针或引用的含义

    将某个变量赋值给指针,实际上就是将这个变量的地址赋值给指针,或者反过来说,指针中存储了这个变量的内存地址,指向了这个变量,通过指针就能找到这个变量。

    在编写链表代码的时候,我们经常会有这样的代码:p->next=q。这行代码是说,p 结点中的 next 指针存储了 q 结点的内存地址。

    还有一个更复杂的,也是我们写链表代码经常会用到的:p->next=p->next->next。这行代码表示,p 结点的 next 指针存储了 p 结点的下下一个结点的内存地址。

    • 警惕指针丢失和内存泄漏

    注意不要把指针弄丢,比如插入是时候

    插入

    在删除的时候要注意,释放内存

    • 利用哨兵简化实现难度

    哨兵
    在处理删除时,head节点比较难处理,所以添加一个哨兵,然后处理完,返回哨兵的next

    • 重点处理边界条件

    经常用来检查链表代码是否正确的边界条件有这样几个:

    1. 如果链表为空时,代码是否能正常工作?
    2. 如果链表只包含一个结点时,代码是否能正常工作?
    3. 如果链表只包含两个结点时,代码是否能正常工作?
    4. 代码逻辑在处理头结点和尾结点的时候,是否能正常工作?
    • 举例画图,辅助思考,多建指针

    写在纸上,把指针赋值和调整之后的结果也画出来,对照写,就比较简单了
    插入

    练习题

    共25个已完成13个,全是中等

    个常见的链表操作:

    • 1.单链表反转 206
      单链表反转
    /**
     * Definition for singly-linked list.
     * function ListNode(val) {
     *     this.val = val;
     *     this.next = null;
     * }
     */
    /**
     * @param {ListNode} head
     * @return {ListNode}
     */
    
    var reverseList = function(head) {
        var prev = null;
        var cur = head;
        var next = null;
        while (cur !== null) {
            next = cur.next;
            cur.next = prev;
            prev = cur;
            cur = next;
        }
        return prev;
    }
    
    // 链表的递归实现
    var reverseList = function(H) {
    	if (H === null || H.next === null)
    		//链表为空直接返回,而H->next为空是递归基
    		return H
    	var newHead = reverseList(H.next) //一直循环到链尾
    	H.next.next = H //翻转链表的指向
    	H.next = null //记得赋值NULL,防止链表错乱
    	return newHead //新链表头永远指向的是原链表的链尾
    }
    
    • 2.链表中环的检测 141
      快慢指针
    使用set来存储
    
    var hasCycle = function(head) {
        const set = new Set();
        if (head == null) {
    		return false;
    	}
        while(head.next !== null) {
            if(set.has(head)) {
                return true;
            } else {
                set.add(head);
            }
            head = head.next;
        }
        return false;
    };
    
    使用快慢指针
    
    var hasCycle = function(head) {
        if (head == null || head.next == null) {
            return false;
        }
        let slow = head;
        let fast = head.next;
        while (slow != fast) {
            if (fast == null || fast.next == null) {
                return false;
            }
            slow = slow.next;
            fast = fast.next.next;
        }
        return true;
    };
    
    • 3.两个有序链表合并 21
    var mergeTwoLists = function(l1, l2) {
        let preHead = new ListNode();
        let cur = preHead;
    
        while (l1 && l2){
            if(l1.val <= l2.val){
                cur.next = new ListNode(l1.val);
                l1 = l1.next;
            }
            else {
                cur.next = new ListNode(l2.val);
                l2 = l2.next;
            }
            cur = cur.next;
        }
        cur.next = l1 || l2
        return preHead.next;
    };
    
    • 4.删除链表倒数第n个节点 19
    var swapPairs = function(head) {
        var dummyHead = new ListNode(0);
        dummyHead.next = head;
        p = dummyHead;
        while(p.next && p.next.next) {
            var node1 = p.next;
            var node2 = p.next.next;
            var next = node2.next;
            
            node2.next = node1;
            node1.next = next;
            p.next = node2;
            
            p = node1
        }
        if (dummyHead.next === null) {
            return []
        }else {
            return dummyHead.next;
        }
        
    };
    
    • 5.求链表的中间节点 876
      快慢指针
    空间换时间  O(n) 空间复杂度:O(N)
    var middleNode = function(head) {
        const arr = [];
        while(head !== null) {
            arr.push(head);
            head = head.next;
        }
        const middle = Math.floor(arr.length / 2);
        return arr[middle];   
    };
    
    快慢指针
    
    var middleNode = function(head) {
        slow = fast = head;
        while (fast && fast.next) {
            slow = slow.next;
            fast = fast.next.next;
        }
        return slow;   
    };
    
    
    
    • 6.两两交换链表中的节点 24 需要补充图
    var swapPairs = function(head) {
        var dummyHead = new ListNode(0);
        dummyHead.next = head;
        p = dummyHead;
        while(p.next && p.next.next) {
            var node1 = p.next;
            var node2 = p.next.next;
            var next = node2.next;
            
            node2.next = node1;
            node1.next = next;
            p.next = node2;
            
            p = node1
        }
        if (dummyHead.next === null) {
            return []
        }else {
            return dummyHead.next;
        }
        
    };
    
    • 7.删除链表中的节点 237
    把下一个的值赋给这个node,然后删除下一个节点即可
    
    var deleteNode = function(node) {
      node.val = node.next.val;
      node.next = node.next.next;
    };
    
    • 8.删除排序链表中的重复元素 83
    因为是有序的,所以直接前一个跟后一个对比删除就行了时间复杂度O(N)
    如何是无序的使用set也可以做到O(N), 就是空间换时间
    
    var deleteDuplicates = function(head) {
        if (head == null) {
            return [];
        }
        let cur = head;
        while(cur && cur.next){
            if (cur.val === cur.next.val) {
                cur.next = cur.next.next
            } else {
                cur = cur.next
            }
        }
        return head;
    };
    
    • 9.移除链表元素 203
    var removeElements = function(head, val) {
        while (head !== null && head.val === val) {
            head = head.next;
        }
        
        if (head === null) {
            return []
        }
        let cur = head;
        while(cur.next !== null) {
            if (cur.next.val === val) {
                cur.next = cur.next.next
            } else {
                cur = cur.next;
            }
        }
        return head;
    };
    
    <!--递归-->
    if (head == null){ 
        return null;
        } 
    head.next = removeElements(head.next,val); 
    return head.val == val ? head.next:head;
        
    // 使用头部守位   然后返回 dummnyHead.next
        
    var removeElements = function(head, val) {
        let dummnyHead = new ListNode(0);
        dummnyHead.next = head;
        let cur = dummnyHead;
        while(cur.next !== null) {
            if (cur.next.val === val) {
                cur.next = cur.next.next
            } else {
                cur = cur.next;
            }
        }
        if (dummnyHead.next === null){
            return []
        } else {
           return dummnyHead.next
        }
    };
    
    • 10.回文链表 234
    快慢针找到中间,然后把后面的翻转,然后对比
    var reverseList = function(head) {
        var pre = null;
        var cur = head;
        var next = null;
        while(cur !== null) {
            next = cur.next;
            
            cur.next = pre;
            
            pre = cur;
            cur = next;
        }
        return pre;
    }
    
    var isPalindrome = function(head) {
        if(head === null || head.next === null) {
            return true;
        }
        fast = slow = head;
        while (fast && fast.next) {
            slow = slow.next;
            fast = fast.next.next;
        }
        if(fast) slow = slow.next;
        let list2 = reverseList(slow);
        while(list2 !== null) {
            if (head.val !== list2.val) {
                return false;
            }
            head = head.next;
            list2 = list2.next;
        }
        return true;
    };
    
    • 11.旋转链表 61
    • 12.相交链表 160
    先变量两个表,然后把长度磨平,然后在对比节点是否相等
    var getIntersectionNode = function(headA, headB) {
        if(headA === null || headB === null) {
            return null;
        }
        var listA = headA;
        var listB = headB;
        
        var lenA = 0;
        var lenB = 0;
        while(listA !== null) {
            listA = listA.next;
            lenA++;
        }
        while(listB !== null) {
            listB = listB.next;
            lenB++;
        }
        if (lenA > lenB) {
            var diff = lenA - lenB;
            while(diff>0) {
                headA = headA.next;
                diff--;
            }
        }
        if (lenB > lenA) {
            var diff = lenB - lenA;
            while(diff>0) {
                headB = headB.next;
                diff--;
            }
        }
        
        while(headB!=null) {
            if(headA==headB)
                return headA;
            headA=headA.next;
            headB=headB.next;
        }
        return null;
    };
    
    public class Solution {
        
        ListNode head;
        Random random;
        
        public Solution(ListNode h) {
            head = h;       
            random = new Random();        
        }
        
        public int getRandom() {
            
            ListNode c = head;
            int r = c.val;
            for(int i=1;c.next != null;i++){
                
                c = c.next;
                if(random.nextInt(i + 1) == i) r = c.val;                        
            }
            
            return r;
        }
    }
    
    var len = 0, curr = root;
        while (curr) {
            len++;
            curr = curr.next;
        }
        var quo = Math.floor(len / k);
        var rem = len % k;
        var results = [root];
        curr = root;
        var last = curr;
    
        while (k > 1) {
            for (var i = 0; i < quo; i++) {
                last = curr;
                curr = curr.next;
            }
            if (rem > 0) {
                last = curr;
                curr = curr.next;
                rem--;
            }
            if (last) {
                last.next = null;    
            }
            results.push(curr);
            k--;
        }
        return results.map(item => item === null ? []: item);
    

    先遍历一遍,拿到长度,然后len / k 就是要分成几个,然后len % k 就是有一个是多1的

    [1,2,3,4,5,6,7,8,9,10]
    ===>
    [4,3,3]

    • 20.删除排序链表中的重复元素 83
    var deleteDuplicates = function(head) {
        if (head == null) {
            return [];
        }
        let cur = head;
        while(cur && cur.next){
            if (cur.val === cur.next.val) {
                cur.next = cur.next.next
            } else {
                cur = cur.next
            }
        }
        return head;
    };
    
    • 21.奇偶链表 328
    • 22.两数相加 2
    var addTwoNumbers = function(l1, l2) {
        if (!l1) return l2
        if (!l2) return l1
        let p1 = l1
        let p2 = l2
        let val, carry
        const ret = new ListNode()
        let cur = ret
        while (p1 || p2) {
            let current = add(p1, p2, carry)
            cur.val = current.val
            carry = current.carry
            if (p1) p1 = p1.next
            if (p2) p2 = p2.next
            if (p1 || p2) {
                cur.next = new ListNode()
                cur = cur.next
            }
        }
        if (carry) {
            cur.next = new ListNode(carry)
        }
        return ret
    };
    
    function add(p1, p2, _carry = 0) {
        let val = ((p1 && p1.val) || 0) + ((p2 && p2.val) || 0) + _carry
        let carry = (val >= 10) ? 1 : 0
        if (carry) { val -= 10 }
        return { val, carry }
    }
    
    • 23.删除排序链表中的重复元素 II82
    • 24.k个一组翻转链表 25
  • 相关阅读:
    第二周进度条博客
    软件工程个人作业01
    动手动脑1
    构建之法阅读笔记06
    构建之法阅读笔记05
    构建之法阅读笔记04
    poj 1631 LIS
    poj 1609 dp
    lightoj 1198 最大权重匹配
    hdu4696 想法题
  • 原文地址:https://www.cnblogs.com/chenjinxinlove/p/10037237.html
Copyright © 2011-2022 走看看