链表题目:交换链表中的结点

文章目录

  • 题目
    • 标题和出处
    • 难度
    • 题目描述
      • 要求
      • 示例
      • 数据范围
  • 前言
  • 解法一
    • 思路和算法
    • 代码
    • 复杂度分析
  • 解法二
    • 思路和算法
    • 代码
    • 复杂度分析

题目

标题和出处

标题:交换链表中的结点

出处:1721. 交换链表中的结点

难度

3 级

题目描述

要求

给你链表的头结点 head \texttt{head} head 和一个整数 k \texttt{k} k

交换链表正数第 k \texttt{k} k 个结点和倒数第 k \texttt{k} k 个结点的值后,返回链表的头结点(链表 1 \texttt{1} 1 开始索引)。

示例

示例 1:

链表题目:交换链表中的结点_第1张图片

输入: head   =   [1,2,3,4,5],   k   =   2 \texttt{head = [1,2,3,4,5], k = 2} head = [1,2,3,4,5], k = 2
输出: [1,4,3,2,5] \texttt{[1,4,3,2,5]} [1,4,3,2,5]

示例 2:

输入: head   =   [7,9,6,6,7,8,3,0,9,5],   k   =   5 \texttt{head = [7,9,6,6,7,8,3,0,9,5], k = 5} head = [7,9,6,6,7,8,3,0,9,5], k = 5
输出: [7,9,6,6,8,7,3,0,9,5] \texttt{[7,9,6,6,8,7,3,0,9,5]} [7,9,6,6,8,7,3,0,9,5]

示例 3:

输入: head   =   [1],   k   =   1 \texttt{head = [1], k = 1} head = [1], k = 1
输出: [1] \texttt{[1]} [1]

示例 4:

输入: head   =   [1,2],   k   =   1 \texttt{head = [1,2], k = 1} head = [1,2], k = 1
输出: [2,1] \texttt{[2,1]} [2,1]

示例 5:

输入: head   =   [1,2,3],   k   =   2 \texttt{head = [1,2,3], k = 2} head = [1,2,3], k = 2
输出: [1,2,3] \texttt{[1,2,3]} [1,2,3]

数据范围

  • 链表中结点的数目是 n \texttt{n} n
  • 1 ≤ k ≤ n ≤ 10 5 \texttt{1} \le \texttt{k} \le \texttt{n} \le \texttt{10}^\texttt{5} 1kn105
  • 0 ≤ Node.val ≤ 100 \texttt{0} \le \texttt{Node.val} \le \texttt{100} 0Node.val100

前言

对于有 n n n 个结点的链表,倒数第 k k k 个结点为正数第 n − k + 1 n - k + 1 nk+1 个结点。定位到链表的第 k k k 个结点和第 n − k + 1 n - k + 1 nk+1 个结点之后,将这两个结点的值交换即可。

定位到链表的倒数第 k k k 个结点有两种做法。第一种做法是首先遍历链表得到链表的结点数量 n n n,然后再次遍历链表定位到链表的第 n − k + 1 n - k + 1 nk+1 个结点;第二种做法是使用两个指针一次遍历定位到链表的倒数第 k k k 个结点。

解法一

思路和算法

首先遍历链表得到链表的结点数量 n n n,然后再次遍历链表,分别定位到链表的第 k k k 个结点和第 n − k + 1 n - k + 1 nk+1 个结点。从 head \textit{head} head 出发,分别向后移动 k − 1 k - 1 k1 次和 n − k n - k nk 次,即可定位到链表的第 k k k 个结点和第 n − k + 1 n - k + 1 nk+1 个结点。

定位到链表的第 k k k 个结点和第 n − k + 1 n - k + 1 nk+1 个结点之后,交换两个结点的值即可。

下图为示例 1 的交换结点的过程。此时 n = 5 n = 5 n=5 k = 2 k = 2 k=2,因此定位到第 2 2 2 个结点和第 4 4 4 个结点,然后交换两个结点的值。

链表题目:交换链表中的结点_第2张图片

代码

class Solution {
    public ListNode swapNodes(ListNode head, int k) {
        int n = 0;
        ListNode temp = head;
        while (temp != null) {
            n++;
            temp = temp.next;
        }
        ListNode node1 = head, node2 = head;
        for (int i = 1; i < k; i++) {
            node1 = node1.next;
        }
        for (int i = 1; i < n - k + 1; i++) {
            node2 = node2.next;
        }
        int val1 = node1.val, val2 = node2.val;
        node1.val = val2;
        node2.val = val1;
        return head;
    }
}

复杂度分析

  • 时间复杂度: O ( n ) O(n) O(n),其中 n n n 是链表的长度。需要遍历链表一次得到链表的结点数量,然后遍历链表分别定位到链表的第 k k k 个结点和第 n − k + 1 n - k + 1 nk+1 个结点。

  • 空间复杂度: O ( 1 ) O(1) O(1)

解法二

思路和算法

上述解法需要首先遍历一次链表得到链表的结点数量 n n n。其实,链表的结点数量 n n n 不需要事先知道。

node 1 \textit{node}_1 node1 node 2 \textit{node}_2 node2 分别表示链表的正数第 k k k 个结点和倒数第 k k k 个结点。从 head \textit{head} head 出发向后移动 k − 1 k - 1 k1 次,即可定位到 node 1 \textit{node}_1 node1。对于 node 2 \textit{node}_2 node2 的定位,可以使用两个指针,这两个指针指向的结点在链表中相差 k k k 个位置。

定位 node 2 \textit{node}_2 node2 时,需要创建临时指针 temp \textit{temp} temp,满足 temp \textit{temp} temp node 2 \textit{node}_2 node2 的后面 k k k 个位置。将 node 2 \textit{node}_2 node2 初始化为 head \textit{head} head,由于 node 1 \textit{node}_1 node1 head \textit{head} head 的后面 k − 1 k - 1 k1 个位置,因此将 temp \textit{temp} temp 初始化为指向 node 1 \textit{node}_1 node1 的后一个结点,即满足 temp \textit{temp} temp node 2 \textit{node}_2 node2 的后面 k k k 个位置;

在初始化 node 2 \textit{node}_2 node2 temp \textit{temp} temp 之后,将 node 2 \textit{node}_2 node2 temp \textit{temp} temp 同时向后移动,直到 temp \textit{temp} temp 指向 null \text{null} null,此时 node 2 \textit{node}_2 node2 即为链表的倒数第 k k k 个结点。

定位到链表的正数第 k k k 个结点和倒数第 k k k 个结点之后,交换两个结点的值即可。

下图为示例 1 的交换结点的过程。此时 k = 2 k = 2 k=2,因此 temp \textit{temp} temp node 2 \textit{node}_2 node2 后面 2 2 2 个位置。同时向后移动 node 2 \textit{node}_2 node2 temp \textit{temp} temp,直到 temp \textit{temp} temp 指向 null \text{null} null node 2 \textit{node}_2 node2 为链表的倒数第 2 2 2 个结点,然后交换 node 1 \textit{node}_1 node1 node 2 \textit{node}_2 node2 的值。

链表题目:交换链表中的结点_第3张图片

代码

class Solution {
    public ListNode swapNodes(ListNode head, int k) {
        ListNode node1 = head;
        for (int i = 1; i < k; i++) {
            node1 = node1.next;
        }
        ListNode node2 = head, temp = node1.next;
        while (temp != null) {
            node2 = node2.next;
            temp = temp.next;
        }
        int val1 = node1.val, val2 = node2.val;
        node1.val = val2;
        node2.val = val1;
        return head;
    }
}

复杂度分析

  • 时间复杂度: O ( n ) O(n) O(n),其中 n n n 是链表的长度。需要遍历链表分别定位到链表的正数第 k k k 个结点和倒数第 k k k 个结点。

  • 空间复杂度: O ( 1 ) O(1) O(1)

你可能感兴趣的:(数据结构和算法,#,链表,链表)