Android开发Android开发经验谈Android技术知识

面试官系列 - LeetCode链表知识点&题型总结

2020-08-01  本文已影响0人  程序员徐公

我的 CSDN 博客:https://blog.csdn.net/gdutxiaoxu

我的掘金:https://juejin.im/user/2207475076966584

github: https://github.com/gdutxiaoxu/

微信公众号:徐公码字(stormjun94)

知乎:https://www.zhihu.com/people/xujun94

前言

前段时间,写了面试必备的一系列文章,反应还不错。有一些读者反馈说,能不能整理一些面试常见的算法。前段时间,我恰好总结了 LeetCode 常见的面试算法题目。

Android 面试必备 - http 与 https 协议

Android 面试必备 - 计算机网络基本知识(TCP,UDP,Http,https)

Android 面试必备 - 线程

Android 面试必备 - JVM 及 类加载机制

Android 面试必备 - 系统、App、Activity 启动过程

面试官系列- 你真的了解 http 吗

面试官问, https 真的安全吗,可以抓包吗,如何防止抓包吗

java 版剑指offer算法集锦

Android_interview github 地址

刚开始准备刷算法题目的时候,感觉真的是好难,十道题目有九道是不会的。心中曾一万只草泥马跑过,自己怎么这么辣鸡。

<img src="https://raw.githubusercontent.com/gdutxiaoxu/blog_pic/master/offer/20200731145019.png"/>

慢慢得,我发现算法也是一个可以通过练习慢慢成长的。

  1. 首先我们要掌握基本的数据结构,数组,链表,哈希表, Set,二叉树,堆,栈等。你要知道他们有什么优缺点,适应场景是什么,时间复杂度和空间复杂度是多少。而不能知道简单的 API。
  2. 接着,掌握了这些基本的数据结构之后,一些基本的算法你也要掌握以下,比如快速排序,归并排序,对排序,二分查找。这些基本的一定要掌握,面试当中经常也会问到。
  3. 分类刷题,我们在力扣上面可以看到,https://leetcode-cn.com/problemset/algorithms/ ,刷题是可以按标签来的。比如链表,数组,二分查找,二叉树,动态规划等
  4. 学好算法不是一日之功,需要长期的积累。建议的做法是每天做一两道题,题目不在多,贵在于理解。坚持一两个月,你会发现你的感觉逐渐好起来了

废话不多说了,开始进入今天的正文,LeetCode链表知识点&题型总结

知识点

什么是链表

​ 链表(Linked List)是一种常见的线性结构。它不需要一块连续的内存空间,通过指针即可将一组零散的内存块串联起来。我们把内存块成为链表的节点,为了将所有的节点串起来,每个链表的节点除了存储数据之外,还需要记录链表的下一个节点的地址,这个记录下个节点地址的指针我们叫做后驱指针。搜索链表需要O(N)的时间复杂度,这点和数组类似,但是链表不能像数组一样,通过索引的方式以O(1)的时间读取第n个数。链表的优势在于能够以较高的效率在任意位置插入或者删除一个节点。

类别

单向链表

​ 每个节点有一个next指针指向后一个节点,还有一个成员变量用于存储数值。单向链表中有两个节点比较特殊,分别是头结点和尾节点。头结点用来记录链表的基地址,知道头结点我们就可以遍历得到整条链表。尾结点的特殊在于指针指向的是一个空指针NULL。

循环链表

​ 循环链表是一种特殊的单链表,与单链表不同的是尾节点不指向空地址,指向链表的头结点。优点是从链尾到链头比较方便,当要处理的数据具有环形结构特点是,非常适合用循环链表来处理。

双向链表

​ 双向链表支持两个方向,每个节点不只有一个后驱指针next指向后面的节点,还有一个前驱指针prev指向前面的节点。

image

双向循环链表

image.png

与数组的性能对比

时间复杂度 数组 链表
插入删除 O(n) O(1)
随机访问 O(1) O(n)

优缺点

常用技巧

题型总结

基本操作

删除类

Given ÷ list: 1->2->3->4->5, and n = 2.

删除链表中导数第二个节点,变成1->2->3->5.

Java

class Solution{
public static ListNode removeNthFromEnd(ListNode head, int n) {
        ListNode dummy = new ListNode(0);
        dummy.next = head;
        ListNode fast = dummy;
        ListNode slow = dummy;
        while(fast.next != null){
            if(n <= 0)
                slow = slow.next;
            fast = fast.next;
            n--;
        }
        if(slow.next != null)
            slow.next = slow.next.next;
        return dummy.next;
    }
}

Leetcode中包含删除类的题目:

序号 题目 难度 代码
19 Remove Nth Node From End of List medium java
82 Remove Duplicates from Sorted List II Medium java
83 Remove Duplicates from Sorted List Easy java
203 Remove Linked List Elements Easy java
237 Delete Node in a Linked List Easy java

翻转类题型

最基础最常在面试中遇到的提醒,206一定要熟练掌握

解题思路:迭代法。

1、我们定义两个指针,分别称之为g(guard 守卫)和p(point)。
我们首先根据方法的参数m确定g和p的位置。将g移动到第一个要反转的节点的前面,将p移动到第一个要反转的节点的位置上。我们以m=2,n=4为例。

image

2、将p后面的元素删除,然后添加到g的后面。也即头插法。

3、根据m和n重复步骤(2)
4、返回dummyHead.next

image.png

递归法:每个节点最多需遍历两次,一次是常规的递归,一次是回溯的递归,所以时间复杂度是O(N),在最坏的情况下,我们需要翻转整个链表,并且递归的方法会占用栈,所以空间复杂度是O(N)

这是两个非常典型而且常见的链表翻转类题目,在面试中也经常出现作为热身题,所以需要重点关注。

Leetcode中包含翻转链表的题目:

序号 题目 难度 代码
25 Reverse Nodes in k-Group Hard java
61 Rotate List Medium java
92 Reverse Linked List II Medium java
206 Reverse Linked List Easy java

合并链表

Java

/*迭代法*/
class Solution{
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
        ListNode head = new ListNode(0);
        ListNode cur = head;
        while (l1 != null && l2 != null) {
            if (l1.val >= l2.val) {
                cur.next = l2;
                l2 = l2.next;
            } else {
                cur.next = l1;
                l1 = l1.next;
            }
            cur = cur.next;
        }
 
        if (l1 != null)
            cur.next = l1;
        if (l2 != null)
            cur.next = l2;
        return head.next;
    }
}

/*递归法*/
class Solution {
    public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
        if (l1 == null) return l2;
        if (l2 == null) return l1;
        if (l1.val > l2.val) {
            ListNode tmp = l2;
            tmp.next = mergeTwoLists(l1, l2.next);
            return tmp;
        } else {
            ListNode tmp = l1;
            tmp.next = mergeTwoLists(l1.next, l2);
            return tmp;
        }
    }
}
class Solution {
   public ListNode mergeKLists(ListNode[] lists) {
        if(lists == null || lists.length == 0) return null;
        return partion(lists, 0, lists.length - 1);
    }

    private ListNode partion(ListNode[] lists, int start, int end) {
        if(start == end) {
            return lists[start];
        }
        else if(start < end) {
            int mid = (start + end) / 2;
            ListNode l1 = partion(lists, start, mid);
            ListNode l2 = partion(lists, mid + 1, end);
            return merge(l1, l2);
        }
        else {
            //not gonna happen.
            return null;
        } 
    }

    private ListNode merge(ListNode l1, ListNode l2) {
        if(l1 == null) return l2;
        if(l2 == null) return l1;
        if(l1.val < l2.val) {
            l1.next = merge(l1.next, l2);
            return l1;
        } else {
            l2.next = merge(l1, l2.next);
            return l2;
        }
    }
}

LeetCode中包含 合并链表类的题目:

序号 题目 难度 代码
2 Add Two Numbers medium java
21 Merge Two Sorted Lists Easy java
23 Merge k Sorted Lists Hard java
445 Add Two Numbers II Medium java

环形链表

Java

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

LeetCode中含有环形链表的题目:

序号 题目 难度 代码
141 Linked List Cycle Easy java
142 Linked List Cycle II Medium java
708 Insert into a Cyclic Sorted List Medium java

拆分链表

Java

class Solution {
    public boolean search(int[] nums, int target) {
        int left = 0, right = nums.length - 1;
        
        while (left <= right) {
            int mid = (left + right) / 2;
            if (target == nums[mid]) return true;
            if (nums[mid] == nums[left]) left++;
            
            else if (nums[mid] > nums[left]) {
                if (nums[left] <= target && nums[mid] > target) right = mid - 1;
                else left = mid + 1;
            } else {
                if (nums[mid] < target && target <= nums[right]) left = mid + 1;
                else right = mid - 1;
            }
        }
        return false;
    }
}

LeetCode中含有拆分类的题目:

序号 题目 难度 代码
725 Split Linked List in Parts Medium java
---- ------------------------------------------------------------ ------ -----------------
86 Partition List Medium java

排序链表

Input: 4->2->1->3

Output: 1->2->3->4

Java

public class Solution {
  
  public ListNode sortList(ListNode head) {
    if (head == null || head.next == null)
      return head;
        
    // step 1.把链表分成两半
    ListNode prev = null, slow = head, fast = head;
    
    while (fast != null && fast.next != null) {
      prev = slow;
      slow = slow.next;
      fast = fast.next.next;
    }
    
    prev.next = null;
    
    // step 2.对于每一部分的链表进行排序
    ListNode l1 = sortList(head);
    ListNode l2 = sortList(slow);
    
    // step 3. 合并 l2 和 l2
    return merge(l1, l2);
  }
  
  ListNode merge(ListNode l1, ListNode l2) {
    ListNode l = new ListNode(0), p = l;
    
    while (l1 != null && l2 != null) {
      if (l1.val < l2.val) {
        p.next = l1;
        l1 = l1.next;
      } else {
        p.next = l2;
        l2 = l2.next;
      }
      p = p.next;
    }
    
    if (l1 != null)
      p.next = l1;
    
    if (l2 != null)
      p.next = l2;
    
    return l.next;
  }

}

LeetCode中 包含链表排序的题目:

序号 题目 难度 代码
143 Reorder List Medium java
---- ------------------------------------------------------------ ------ -----------------
147 Insertion Sort List Medium java
148 Sort List Medium java

小结

链表的问题是面试当中常常会问到的,比如链表的倒置,删除链表中某个结点,合并两个排序链表,合并 k 个排序链表,排序两个无序链表等。

这些题目一般有一些相应的技巧可以解决。

第一,引入哨兵结点。如我们开头说的 dummy node 结点。在任何时候,不管链表是不是空,head结点都会一直指向这个哨兵结点。我们也把这种有哨兵结点的链表叫做带头链表。

第二,双指针法。这种用法适用于查找链表中某个位置,判断链表是否有环等

第三,分之归并法。这种用法适用于链表的排序处理,如合并 k 个排序链表,排序两个无序链表等。

第四,在解答的过程中,要多考虑边界情况。

参考资料:

1.https://leetcode-cn.com/problems/sort-list/discuss/46714/Java-merge-sort-solution

2.https://leetcode-cn.com/problems/merge-two-sorted-lists/discuss/9735/Python-solutions-(iteratively-recursively-iteratively-in-place).

往期文章

Android 面试必备 - http 与 https 协议

Android 面试必备 - 计算机网络基本知识(TCP,UDP,Http,https)

Android 面试必备 - 线程

Android 面试必备 - JVM 及 类加载机制

Android 面试必备 - 系统、App、Activity 启动过程

面试官系列- 你真的了解 http 吗

面试官问, https 真的安全吗,可以抓包吗,如何防止抓包吗

java 版剑指offer算法集锦

Android_interview github 地址 帮忙 star

如果你觉得对你有所帮助的话,可以关注我的公众号 徐公码字(stormjun94),第一时间会在上面更新

image
上一篇 下一篇

猜你喜欢

热点阅读