leetcode刷题思路-----链表

leetcode刷题思路-----链表

1. 基本模板

单链表的问题没什么模板,大家按照自己习惯都有各自的方法去删除,插入等。
对于力扣的问题也没有太难的题,都是基本的方法的组合,比如从反转链表到k个一组反转链表,合并两个链表到合并k个有序链表,我们从最基本的开始。

建立ListNode类

public class ListNode {
    int val;
    ListNode next;
    public ListNode(){}
    //给两个有参构造,方便建立普通节点和哨兵节点
    public ListNode(int val){
        this.val = val;
    }
    public ListNode(int val,ListNode next){
        this.val = val;
        this.next = next;
    }
	//重写了toString方法,本地ide调试看起来舒服一点
    @Override
    public String toString() {
        return "" +
                "" + val +
                "->" + next
                ;
    }
}

按照数组建立单链表

private static ListNode BuildNode(int[] nums){
		//建立哨兵节点
        ListNode new_head = new ListNode(-1);
        ListNode cur = new_head;
        //按照数组尾插节点进来
        for (int val: nums) {
            ListNode temp = new ListNode(val);
            cur.next = temp;
            cur = temp;
        }
        return new_head.next;
    }

反转链表

本文给出原地反转的方法,还有递归的方法等。

	//反转链表
    private  static ListNode reverse(ListNode head){
    	//通过cur对链表遍历,将该节点指向前一个pre节点
        ListNode pre = null;
        ListNode cur = head;
        //遍历链表
        while(cur!=null){
        	//保存下一个节点,防止丢失
            ListNode new_cur = cur.next;
            cur.next = pre;
            pre = cur;
            cur = new_cur;
        }
        //返回头节点,此时头节点就是pre
        return pre;
    }

合并链表

对于合并两个有序链表的思路:
建立一个头节点和指针pre,对于两个链表的头节点进行比较,较小的加入pre的next。
对于
l1={1,2,4};
l2={3,5}
两个链表:

简单流程

 	//合并链表
    private static ListNode merge(ListNode head,ListNode head1){
    	//哨兵节点,方便返回头节点
        ListNode new_head = new ListNode(-1);
        ListNode pre = new_head;
        //选最小的加入新链表
        while(head!=null&&head1!=null){
            if(head.val< head1.val){
                pre.next = head;
                head = head.next;
            }else{
                pre.next = head1;
                head1 = head1.next;
            }
            pre = pre.next;
        }
        //剩下的链表直接加入尾部
        pre.next =  head ==null ? head1 : head;
        //返回新链表头节点
        return  new_head.next;
    }

删除链表重复数字

private static ListNode Mydelete(ListNode head){
        ListNode new_head = new ListNode(-1,head);
        ListNode pre = new_head;
        ListNode cur = head;
        while(cur!=null){
        	//找到重复的一直走到最后
            while(cur.next!=null&&cur.val==cur.next.val){
                cur = cur.next;
            }
            //删除之前的重复的,若没有的重复的,相当于重新指向了下一个节点
            pre.next = cur;
            pre = cur;
            cur = cur.next;

        }
        return new_head;
    }

2. 进阶

2.1 合并k个有序链表

思路就是合并两个有序链表,加上归并排序的思路:

class Solution {
    public ListNode mergeKLists(ListNode[] lists) {
        return sort(lists,0,lists.length-1);

    }
    //归并或者分治的思路
    private ListNode sort(ListNode[] lists,int left,int right){
    	//一直分割到剩一个节点
        if(left==right){
            return lists[left];
        }else{
            int mid  = (left+right)/2;
            ListNode l = sort(lists,left,mid);
            ListNode r = sort(lists,mid+1,right);
            //合并并且递归
            return mergeTwo(l,r);
        }
    }
	//合并两个有序链表
    private ListNode mergeTwo(ListNode l1, ListNode l2){
        ListNode new_head = new ListNode(-1);
        ListNode pre = new_head;
        while(l1!=null&&l2!=null){
            if(l1.val<l2.val){
                pre.next = l1;
                l1 = l1.next;
            }else{
                pre.next = l2;
                l2 = l2.next;
            }
            pre = pre.next;
        }
        pre.next = l1==null ? l2 : l1;
        return new_head.next;
    }
}

2.2 k个一组反转链表

class Solution {
    public ListNode reverseKGroup(ListNode head, int k) {
        if(head==null||head.next==null){
            return head;
        }
        //先用哨兵节点
        ListNode new_head = new ListNode(-1,head);
        //pre代表反转的链表的前置节点
        ListNode pre = new_head;
        //cur代表当前链表的尾部
        ListNode cur = new_head;
        while(cur.next!=null){
        	//找到当前组的尾部
            for(int i=0; i<k&&cur!=null; i++){
               cur = cur.next;
            }
            //如果不够长度直接返回
            if(cur==null){
                break;
            }
            //断链之前保存下一个节点
            ListNode new_cur = cur.next;
            //必须断链,否则后边的一起反转了
            cur.next = null;
            ListNode[] ls = reverse(pre.next);
            //指向反转后的链表
            pre.next = ls[0];
            //到链表尾部,准备下一次反转
            pre = ls[1];
            cur = pre;
            //将断链接上
            cur.next = new_cur;
        }
        return new_head.next;

    }
    //反转链表,这次将尾部也存入返回,以便继续向下走
    private ListNode[] reverse(ListNode head){
        ListNode head1 = head;
        ListNode pre = null;
        ListNode cur = head;
        while(cur!=null){
            ListNode new_cur = cur.next;
            cur.next = pre;
            pre = cur;
            cur = new_cur;
        }
        return new ListNode[]{pre,head1};
    }
}

总结:链表的题并没有太大的难度,主要就是遍历,插入,删除比如和递归,排序的结合。
关于合并排序可以参照:leetcode刷题思路-----排序

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值