链表

我的博客:blog.koreyoshi.work

链表是一种物理存储单元上非连续、非顺序的存储结构数据元素的逻辑顺序是通过链表中的指针链接次序实现的。链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成。每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域。 相比于线性表顺序结构,操作复杂。由于不必须按顺序存储,链表在插入的时候可以达到O(1)的复杂度,比另一种线性表顺序表快得多,但是查找一个节点或者访问特定编号的节点则需要O(n)的时间,而线性表和顺序表相应的时间复杂度分别是O(logn)和O(1)。

剑指offer 和 LeetCode 中的相关题目做一个汇总,感谢尾尾部落,从部落中学习转载。

https://www.weiweiblog.cn

 

1.反转链表

题目描述:输出一个单链表的逆序反转后的链表。 解题思路:用三个临时指针 prev、cur、next 在链表上循环一遍即可。

[剑指offer] 从尾到头打印链表 [剑指offer] 反转链表

public ListNode preListNode(ListNode node){
   ListNode head = node;
   ListNode pre = head.next;
   while(pre != null){
       ListNode tmp = pre.next;
       // 接在后面
       pre.next = head;
       // 给回head
       head = pre;
       pre = tmp;
  }
   node.next = null;
   return head;
}

2.旋转链表(将链表向右旋转 K 个位置)

题目描述:给定一个单链表,设计一个算法实现链表向右旋转 K 个位置。 举例: 给定 1->2->3->4->5->6->NULL, K=3 则4->5->6->1->2->3->NULL 解题思路

  • 方法一 双指针,快指针先走k步,然后两个指针一起走,当快指针走到末尾时,慢指针的下一个位置是新的顺序的头结点,这样就可以旋转链表了。

  • 方法二 先遍历整个链表获得链表长度n,然后此时把链表头和尾链接起来,在往后走n – k % n个节点就到达新链表的头结点前一个点,这时断开链表即可。

方法二代码:

public ListNode 旋转链表(ListNode node, int k){
       if (node == null){
           return null;
      }
       ListNode pre = node;
       int n = 1;
       while (pre.next != null){
           n++;
           pre = pre.next;
      }
       pre.next = node;
       int m = n - k%n;
       for (int i = 0; i < m; i++){
           pre = pre.next;
      }
       ListNode newNode = pre.next;
       pre.next = null;
       return newNode;
  }

3.求单链表的中间节点

题目描述:求单链表的中间节点,如果链表的长度为偶数,返回中间两个节点的任意一个,若为奇数,则返回中间节点。 解题思路:快慢指针,慢的走一步,快的走两步,当快指针到达尾节点时,慢指针移动到中间节点。

public static ListNode 单链表的中间节点(ListNode head){
       if (head == null){
           return null;
      }
       ListNode slow = head;
       ListNode fast = head;
       while (fast != null && fast.next != null){
           fast = fast.next.next;
           slow = slow.next;
      }
       return slow;
  }

4.链表划分

题目描述: 给定一个单链表和数值x,划分链表使得所有小于x的节点排在大于等于x的节点之前。

摘除法:

public ListNode 划分(ListNode head, int k){
       ListNode rightDummy = new ListNode(0);
       ListNode leftDummy = new ListNode(0);
       ListNode left = leftDummy, right = rightDummy;
       while (head != null){
           if (head.val < k){
               left.next = head;
               left = head;
          } else {
               right.next = head;
               right = head;
          }
           head = head.next;
      }
       right.next = null;
       left.next = rightDummy.next;
       return leftDummy.next;
  }

5.链表求和

题目描述:你有两个用链表代表的整数,其中每个节点包含一个数字。数字存储按照在原来整数中相反的顺序,使得第一个数字位于链表的开头。写出一个函数将两个整数相加,用链表形式返回和。 解题思路:做个大循环,对每一位进行操作:

当前位:(A[i]+B[i])%10 进位:(A[i]+B[i])/10

public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
       ListNode d = new ListNode(0);
       ListNode res = d;
       int sum = 0;
       ListNode l = l1;
       ListNode r = l2;
       while (l != null || r != null){
           if (l != null){
               sum += l.val;
               l = l.next;
          }
           if (r != null){
               sum += r.val;
               r = r.next;
          }
           res.next = new ListNode(sum%10);
           sum = sum/10;
           res = res.next;
      }
       if (sum != 0){
           res.next = new ListNode(sum%10);
      }
       return d.next;
  }

6.单链表排序

题目描述:在O(nlogn)时间内对链表进行排序。

 

posted @ 2019-09-24 22:40  heroic_zjx  阅读(413)  评论(0编辑  收藏  举报