算法通关2.数组和链表

数组

数组:内存里连续的一段存储区域

取:取元素时间复杂度为O(1)

插入:需要挪动插入位置后面的元素,时间复杂度为O(n)

删除:同插入,后面的元素需要向前挪动,时间复杂度为O(n)

链表

单向链表:用一个指针链向下一个元素

双向链表:用俩个指针链向上一个元素和下一个元素

增加删除只需要更改指针指向即可,时间复杂度O(1)

查找时间复杂度是O(n)

练习

  1. leetcode206反转链表

    输入: 1->2->3->4->5->NULL
    输出: 5->4->3->2->1->NULL
    

    思路:定义俩个变量,记录当前节点和上一个节点,采用俩数交换的方式进行反转

    class Solution {
        public ListNode reverseList(ListNode head) {
            ListNode cur = head;
            ListNode prev = null;
            ListNode tempNext = null;
            while (cur != null) {
                tempNext = cur.next;
                cur.next = prev;
                prev = cur;
                cur = tempNext;
            }
            return prev;
        }
    }
    
  2. leetcode24两两交互链表中的节点

    给定 1->2->3->4, 你应该返回 2->1->4->3.
    

    递归解乏

        public static ListNode swapPairs(ListNode head) {
            if (head == null || head.next == null) {
                return head;
            }
            ListNode next = head.next;
            head.next = swapPairs(next.next);
            next.next = head;
            return next;
        }
    

    非递归解法

        public static ListNode swapPairs2(ListNode head) {
            ListNode prev = new ListNode(0);
            prev.next = head;
            ListNode temp = prev;
            while (temp.next != null && temp.next.next != null) {
                ListNode start = temp.next;
                ListNode end = temp.next.next;
                temp.next = end;
                start.next = end.next;
                end.next = start;
                temp = start;
            }
            return prev.next;
        }
    
  3. 环形链表

    给定一个链表,判断链表中是否有环。

    输入:head = [3,2,0,-4], pos = 1
    输出:true
    解释:链表中有一个环,其尾部连接到第二个节点。
    
    img

思路:如何判断一个链表是否有环

  1. 硬做(在0.5s内判断会不会走到null,性能很差)

  2. 把走过的节点放到set中,每到新节点判断set中有没有进行判重,时间复杂度O(n)

        public boolean hasCycle(ListNode head) {
            Set<ListNode> nodes = new HashSet<>();
            while (head != null) {
                if (nodes.contains(head)) {
                    return true;
                }
                nodes.add(head);
                head = head.next;
            }
            return false;
        }
    
  3. 龟兔赛跑式(快慢指针),快指针每次走俩步,慢指针每次走一步,快慢相遇说明有环

        public boolean hasCycle(ListNode head) {
            if (head == null || head.next == null) {
                return false;
            }
            ListNode fast = head;
            ListNode slow = head;
            while (fast.next != null && fast.next.next != null) {
                slow = slow.next;
                fast = fast.next.next;
                if (slow == fast) {
                    return true;
                }
            }
            return false;
        }
    

推荐阅读更多精彩内容