单链表相关算法2_24
Leetcode 328 奇偶链表
给定一个单链表,把所有的奇数节点和偶数节点分别排在一起。请注意,这里的奇数节点和偶数节点指的是节点编号的奇偶性,而不是节点的值的奇偶性。
请尝试使用原地算法完成。你的算法的空间复杂度应为 O(1),时间复杂度应为 O(nodes),nodes 为节点总数。
实现策略:
创建两个单链表,一个链表用于存放奇数点,一个链表用于存放偶数点,之后将奇数链的最后一个节点与偶数链的第一个节点相连接即可。
public ListNode oddEvenList(ListNode head) { if(head==null || head.next==null) { return head; } // 创建两个新的空链表 ListNode odd=new ListNode(0); ListNode oddfirst=odd; ListNode even=new ListNode(0); ListNode evenfirst=even; int i=0; while(head!=null){ i++; if(i%2==1){ ListNode oddcurr=new ListNode(head.val); odd.next=oddcurr; odd=oddcurr; } else{ ListNode evencurr=new ListNode(head.val); even.next=evencurr; even=evencurr; } head=head.next; } // 将奇数链的最后一个节点与偶数链的第一个节点进行相连 odd.next=evenfirst.next; evenfirst.next=null; return oddfirst.next; }
Leetcode 2: 两数相加
给出两个 非空 的链表用来表示两个非负的整数。其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字。
如果,我们将这两个数相加起来,则会返回一个新的链表来表示它们的和。
您可以假设除了数字 0 之外,这两个数都不会以 0 开头。
实现思路:
/* * Input: (2 -> 4 -> 3) + (5 -> 6 -> 4) Output: 7 -> 0 -> 8 * * */ /* * 分析:这里面存在几个问题: *l1与l2等长的时候;以及l1与l2不等长的情况 * * */ public ListNode addTwoNumbers(ListNode l1, ListNode l2) { if(l1==null && l2==null){ return null; } ListNode result=new ListNode(0); ListNode first=result; int flag=0; while(l1!=null && l2!=null){ int sum=l1.val+l2.val+flag; flag=0; ListNode current=new ListNode(sum%10); result.next=current; result=current; if(sum>9){ flag=1; } l1=l1.next; l2=l2.next; } if(l1==null){ while(l2!=null){ int sum=l2.val+flag; flag=0; if(sum>9){ flag=1; } ListNode current=new ListNode(sum%10); result.next=current; result=current; l2=l2.next; } } if(l2==null){ while(l1!=null){ int sum=l1.val+flag; flag=0; if(sum>9){ flag=1; } ListNode current=new ListNode(sum%10); result.next=current; result=current; l1=l1.next; } } if(flag==1){ ListNode flagnode=new ListNode(flag); result.next=flagnode; } return first.next; }
小结一个点:
头插链表:
有三个节点:
节点1------节点2-----节点3------.......
(head) (prev) (cur)
实现代码:
prev.next=cur.next;
cur.next=head.next;
head.next=cur;
cur.next=prev.next;
注意其顺序,方便记忆。
应用1:反转链表使用头插法进行:(由于head节点不空,可以声明一个-1节点,使其指向head节点,作为上面的head节点):
public ListNode reverseList(ListNode head) { if(head==null){ return null; } if(head.next==null){ return head; } ListNode empty=new ListNode(-1); empty.next=head; ListNode cur=head.next; while(cur!=null){ head.next=cur.next; cur.next=empty.next; empty.next=cur; cur=head.next; } return empty.next; }
应用2:Leetcode 92: 反转链表 II
反转从位置 m 到 n 的链表。请使用一趟扫描完成反转。
实现策略:
设置一个新的节点,指向链表头结点,将m到n之间元素按照上述策略进行头插操作。返回声明节点的next节点即可。
public ListNode reverseBetween(ListNode head, int m, int n) { ListNode dummy=new ListNode(-1); dummy.next=head; ListNode prev=dummy; for(int i=0;i<m-1;i++){ prev=prev.next; } ListNode head2=prev; prev=head2.next; ListNode cur=prev.next; for(int i=m;i<n;i++){ prev.next=cur.next; cur.next=head2.next; head2.next=cur; cur=prev.next; } return dummy.next; }
Leetcode 86: 分隔链表
给定一个链表和一个特定值 x,对链表进行分隔,使得所有小于 x 的节点都在大于或等于 x 的节点之前。
你应当保留两个分区中每个节点的初始相对位置。
实现原理:类似于之前奇偶链表,创建两个链表min和max,最后进行拼接即可。
public ListNode partition(ListNode head, int x) { if(head==null){ return null; } // 创建两个链表头 ListNode min=new ListNode (-1); ListNode result=min; ListNode max=new ListNode(-1); ListNode maxpre=max; while(head!=null){ if(head.val<x){ ListNode mincur=new ListNode(head.val); min.next=mincur; min=mincur; } else{ ListNode maxcur=new ListNode(head.val); max.next=maxcur; max=maxcur; } head=head.next; } // 实现拼接 min.next=maxpre.next; maxpre.next=null; return result.next; }
Leetcode 83 : 删除排序链表中的重复元素
给定一个排序链表,删除所有重复的元素,使得每个元素只出现一次。
实现原理:注意这里的链表是初始有序的。创建一个新的链表,current记录当前元素的值,由于链表有序,如果当前节点的值大于current,则直接更新current,否则就继续。
public ListNode deleteDuplicates(ListNode head) { if(head==null) return null; ListNode result=new ListNode(-1); ListNode prev=result; int current = Integer.MIN_VALUE; while(head!=null){ if(head.val!=current){ ListNode node=new ListNode(head.val); result.next=node; result=node; current=head.val; } head=head.next; } return prev.next; }
Leetcode 82: 删除排序链表中的重复元素 II
给定一个排序链表,删除所有含有重复数字的节点,只保留原始链表中 没有重复出现 的数字。
实现原理:相较于I,这里设置了两个指针点,prev与cur,cur表示的是当前节点位置,prev保证其之前的元素是结果元素。
加了一重循环,找到第一个合适的cur点,将prev的指针指向cur点。
public ListNode deleteDuplicates2(ListNode head) { if(head==null || head.next==null){ return head; } ListNode result=new ListNode(-1); result.next=head; ListNode prev=result; ListNode cur=head; while(cur!=null && cur.next!=null) { if(cur.val!=cur.next.val){ prev=cur; cur=cur.next; } else{ while(cur.next!=null && cur.val==cur.next.val){ cur=cur.next; } prev.next=cur.next; cur=cur.next; } } return result.next; }