首页 > 技术文章 > 单链表相关算法2_24

qian2015 2019-02-24 17:20 原文

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;
    	
}

  

 

推荐阅读