淺談數據結構之線性表基礎算法和麪試真題(二)

上一篇

線性表的基礎概念和結構請參考上一篇,ListNode 結構請參考上一篇,本篇討論線性表的幾個算法,開闊算法思路。

線性表反轉算法

算法描述:線性表反轉,就是由原來的前一個節點指向後一個節點,變成後一個節點指向前一個節點,例如1,2,3,4的順序,反轉成4,3,2,1。

    /**
	 * 反轉鏈表
	 * 時間複雜度O(n),空間複雜度O(1)
	 * @param head
	 * @return
	 */
	public static ListNode reverseList(ListNode head) {
		ListNode pre = null;//上一個節點
		ListNode next = null;//下一個節點
		while (head != null) {
			next = head.next;//獲取下一個節點,記錄下來
			head.next = pre;//把當前節點反轉指向上一個節點
			pre = head;//上一個節點後移一位
			head = next;//當前節點後移一位,處理下一個節點
		}
		return pre;
	}

線性表取中間節點

算法描述:如果線性表是1,2,3,4,5,則算法輸出的是3的節點,如果是1,2,3,4,算法輸出的2。假設定義兩個變量,一個一次增加2,一個一次增加1,那麼當第一個變量走到末尾的時候,第二個變量剛好到中間。

    /**
	 * 取中間節點(偶數取得中間節點前面得那個)
	 * 時間複雜度O(2/n),空間複雜度O(1)
	 * @param head
	 */
	public static ListNode getMid(ListNode head) {
		if (head == null) {
			return head;
		}
		ListNode fast = head;
		ListNode slow = head;
		while (fast.next != null && fast.next.next != null) {
			slow = slow.next;
			fast = fast.next.next;
		}
		return slow;		
	}

兩個有序線性表合併

兩個有序線性表,如一個是1,3,5另一個是2,4,6,合併之後是1,2,3,4,5,6.

遞歸算法

    /**
	 * 採用遞歸
	 * @param head1
	 * @param head2
	 * @return
	 */
	public static ListNode mergeTwoList(ListNode head1, ListNode head2) {
		if (head1 == null && head2 == null) {
			return null;
		}
		
		if (head1 == null) {
			return head2;
		} 
		
		if (head2 == null) {
			return head1;
		}
		
		ListNode head = null;
		if (head1.value > head2.value) {//說明第一個值是取得head2,就要把head2往後移,遞歸
			head = head2;
			head.next = mergeTwoList(head1, head2.next);
		} else { //說明第一個值是取得head1,就要把head1往後移,遞歸
			head = head1;
			head.next = mergeTwoList(head1.next, head2);
		}
		return head;
	}

非遞歸算法

    /**
	 * 非遞歸
	 * @param head1
	 * @param head2
	 * @return
	 */
	public static ListNode mergeTwoList2(ListNode head1, ListNode head2) {
		if (head1 == null || head2 == null) {
			return head1 != null ? head1 : head2;
		}
		
		//存儲排序後的鏈表
		ListNode head = head1.value < head2.value ? head1 : head2;
		//記錄head1
		ListNode cur1 = head == head1 ? head1 : head1;
		//記錄head2
		ListNode cur2 = head == head1 ? head2 : head1;
		
		ListNode pre = null;//cur1前一個元素
		ListNode next = null;//cur2後一個元素
		while (cur1 != null && cur2 != null) {
			if (cur1.value <= cur2.value) {
				pre = cur1;
				cur1 = cur1.next;
			} else {
			    // 把cur2合併到cur1,相當於插入操作
				next = cur2.next;
				pre.next = cur2;
				cur2.next = cur1;
				pre = cur2;
				cur2 = next;
			}
			
		}
		//判斷是不是其中一個已經結束
		pre.next = cur1 == null? cur2:cur1;
		return head;
	}

面試真題

鏈表排序

描述:一個鏈表,奇數位升序,偶數位降序,對鏈表進行排序,例如:183654729,排序後123456789,要求,空間複雜度O(n);
思路:
1.按照奇數位和偶數位拆分成兩個鏈表
2.對偶數位反轉
3.將兩個有序鏈表進行合併
按照如上的思路,是不是把問題分解成了幾個簡單的鏈表操作。直接上代碼:

/**
	 * 分三步
	 * 1.按照奇數位和偶數位拆分成兩個鏈表
	 * 2.對偶數位反轉
	 * 3.將兩個有序鏈表進行合併
	 */
	
	public static ListNode[] getLists(ListNode head) {
		ListNode head1 = null;
		ListNode head2 = null;
		
		ListNode cur1 = null;
		ListNode cur2 = null;
		
		int count = 1;
		while( head != null) {
			if (count % 2 == 1) {
				if (cur1 != null) {
					cur1.next = head;
					cur1 = cur1.next;
				} else {
					cur1 = head;
					head1 = cur1;
				}
			} else {
				if (cur2 != null) {
					cur2.next = head;
					cur2 = cur2.next;
				} else {
					cur2 = head;
					head2 = cur2;
				}
			}
			head = head.next;
			count++;
		}
		
		cur1.next = null;
		cur2.next = null;
		
		ListNode[] nodes = new ListNode[] {head1, head2};
		return nodes;		
	}
	
	/**
	 * 鏈表2反轉
	 * @param head
	 * @return
	 */
	public static ListNode reverseList(ListNode head) {
		ListNode pre = null;//上一個節點
		ListNode next = null;//下一個節點
		while (head != null) {
			next = head.next;
			head.next = pre;
			pre = head;
			head = next;
		}
		return pre;
	}
	
	
	/**
	 * 採用遞歸合併
	 * @param head1
	 * @param head2
	 * @return
	 */
	public static ListNode mergeTwoList(ListNode head1, ListNode head2) {
		if (head1 == null && head2 == null) {
			return null;
		}
		
		if (head1 == null) {
			return head2;
		} 
		
		if (head2 == null) {
			return head1;
		}
		
		ListNode head = null;
		if (head1.value > head2.value) {
			head = head2;
			head.next = mergeTwoList(head1, head2.next);
		} else {
			head = head1;
			head.next = mergeTwoList(head1.next, head2);
		}
		
		return head;
	}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章