JAVA数据结构-链表算法题 21. 合并两个有序链表 剑指 Offer 22. 链表中倒数第k个节点 剑指 Offer 06. 从尾到头打印链表 剑指 Offer 24. 反转链表

JAVA数据结构-单链表 算法题

21. 合并两个有序链表

题目:将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。

输入:1->2->4, 1->3->4
输出:1->1->2->3->4->4

方法:

  1. 循环比较两链表的首个数据节点,将较小的值插入新链表.
  2. 类似于插入排序,以一个链表L1作为基础,将另外一个链表L2的节点不断遍历比较并插入L1.
  3. 将两链表相连,直接进行排序操作 (超时)

方法一思路:

  • 创建一个只有头节点的新链表L3,创建临时指针t1 t2和t3分别指向L1和L2和L3;
  • 循环比较t1和t2的值,将较小的一个节点连接在L3的末尾,使T3和较小值链表指针(t1或t2)后移一位;
  • 当t1或t2后移后节点为空时,循环结束,将指针位空的队列相应的标识符flag置为true;
  • 将遍历结束以后多的哪一个队列的剩余元素添加到L3尾部;
  • 返回L3.next

代码:

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    
    
    public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
    
    
        if(l1 == null){
    
    
            return l2;
        }
        if(l2 == null){
    
    
            return l1;
        }
        ListNode head = new ListNode(0,null);
        ListNode tempHead = head;
        boolean flag1 = false;
        boolean flag2 = false;
        while(true){
    
    
            if(l1.val >= l2.val){
    
    
                tempHead.next = l2;
                l2 = l2.next;
                tempHead = tempHead.next;
                if(l2 == null){
    
    
                    flag2 = true;
                    break;
                }
            }else{
    
    
                tempHead.next = l1;
                l1 = l1.next;
                tempHead = tempHead.next;
                if(l1 == null){
    
    
                    flag1 = true;
                    break;
                }
            }
        }
        if(flag1){
    
    
            tempHead.next = l2;
        }
        if(flag2){
    
    
            tempHead.next = l1;
        }
        return head.next;
    }
}

使用递归的方法实现:

递归能简化代码,但是栈的开销比较大,并且递归层次太深会报栈溢出异常.

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
    
    
        if (l1 == null) return l2;
        if (l2 == null) return l1;
        ListNode res = l1.val < l2.val ? l1 : l2;
        res.next = mergeTwoLists(res.next, l1.val >= l2.val ? l1 : l2);
        return res;
    }

剑指 Offer 22. 链表中倒数第k个节点

题目:输入一个链表,输出该链表中倒数第k个节点。为了符合大多数人的习惯,本题从1开始计数,即链表的尾节点是倒数第1个节点。例如,一个链表有6个节点,从头节点开始,它们的值依次是1、2、3、4、5、6。这个链表的倒数第3个节点是值为4的节点。

给定一个链表: 1->2->3->4->5, 和 k = 2.
返回链表 4->5.

方法:

  1. 根据链表总共长度和k计算出需要返回节点的起始位置
  2. 使用快慢指针思想实现

方法一思路:

  1. 先把链表从头到尾遍历,得到链表有效节点的总长度lenth
  2. 使用length减去k得到开始遍历的倒数数的起始位置. start= length - k
    1. 需要判断length=0,传入链表为空
    2. start=0, k等于链表总长度,直接返回原链表
    3. start<0,k值大于链表总长度,返回null
    4. start>0,正常情况,从start开始遍历

代码:

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    
    
    public ListNode getKthFromEnd(ListNode head, int k) {
    
    
        //length =0
        if(head == null){
    
    
            return null;
        }
        //计算length
        ListNode temp = head;
        int length = 0;
        while(true){
    
    
            if(temp == null) break;
            temp = temp.next;
            length++;
        }
        //计算开始位置
        int start = length - k;
        if(start <0) {
    
    
            return null;
        }else if(start ==0){
    
    
            return head;
        }
        //定位到start位置
        temp = head;
        while((start--) != 0){
    
    
            temp = temp.next;
        }
        return temp;
    }
}

方法二思路:

  • 设置两个快慢指针front和behind,分别指向头数据节点
  • 先让快指针走k步
  • 然后两个指针同时走,当快指针走到头时,慢指针就是链表的倒数第k个节点.

代码:

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    
    
    public ListNode getKthFromEnd(ListNode head, int k) {
    
    
       ListNode frontNode = head, behindNode = head;
        while (frontNode != null && k > 0) {
    
    

            frontNode = frontNode.next;
            k--;
        }

        while (frontNode != null) {
    
    

            frontNode = frontNode.next;
            behindNode = behindNode.next;
        }

        return behindNode;
    }
}

剑指 Offer 24. 反转链表

题目:定义一个函数,输入一个链表的头节点,反转该链表并输出反转后链表的头节点。

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

方法:

  1. 头插法
  2. 借助栈

方法一思路:

  • 先定义一个反转后链表的头节点reverseHead
  • 遍历原来的链表head,每遍历一个节点,就将其取出,并放在新的链表reverseHead的最前端
  • 返回reverseHead.next

代码:

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    
    
    public ListNode reverseList(ListNode head) {
    
    
        if(head == null || head.next == null){
    
    
            return head;
        }
        ListNode reverseHead = new ListNode(0);
        ListNode count = head;
        while(true){
    
    
            if(count == null) break;
            //将count指向的数据节点拿出
            ListNode temp = count;
            count =count.next;
            //插入到reverseHead的第一个数据元素
            temp.next = reverseHead.next;
            reverseHead.next = temp;
        }
        return reverseHead.next;
    }
}

剑指 Offer 06. 从尾到头打印链表

题目:输入一个链表的头节点,从尾到头反过来返回每个节点的值(用数组返回)。

输入:head = [1,3,2]
输出:[2,3,1]

方法:

  1. 反转链表再打印,这样做的问题是回破坏原来的单链表结构,不建议
  2. 利用栈的特性,实现逆序打印
  3. 根据数组下标,反向插入数据,实现逆序

方法二思路:

  • 遍历链表中的每一个节点,将节点的数据压入栈中,并计数count
  • 创建count大小的数据,遍历数据,将pop出的结果放入指定下标位置.

代码:

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    
    
    public int[] reversePrint(ListNode head) {
    
    
        Stack<Integer> stack = new Stack();
        ListNode temp = head;
        int count=0;
        while(temp != null){
    
    
            stack.push(temp.val);
            temp = temp.next;
            count++;
        }
        int [] result = new int [count];
        for(int i=0;i<count;i++){
    
    
            result[i] = stack.pop();
        }
        return result;
    }
}

方法三思路:

  • 遍历链表统计出节点数count,创建长度为cont的数组
  • 逆序遍历数组插入数据

代码:

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    
    
    public int[] reversePrint(ListNode head) {
    
    
       ListNode node = head;
        int count = 0;
        while (node != null) {
    
    
            ++count;
            node = node.next;
        }
        int[] nums = new int[count];
        node = head;
        for (int i = count - 1; i >= 0; --i) {
    
    
            nums[i] = node.val;
            node = node.next;
        }
        return nums;
    }
}

猜你喜欢

转载自blog.csdn.net/weixin_44634197/article/details/108421438