菜雞每日一題系列打卡86天
每天一道算法題目
小夥伴們一起留言打卡
堅持就是勝利,我們一起努力!
題目描述(引自LeetCode)
給定一個鏈表和一個特定值x,對鏈表進行分隔,使得所有小於x的結點都在大於或等於x的結點之前。
你應當保留兩個分區中每個結點的初始相對位置。
示例:
輸入: head = 1->4->3->2->5->2, x = 3
輸出: 1->2->2->4->3->5
題目分析
這是一道鏈表的題目,菜雞將採用迭代的方式進行解決,通過一定的指針操作,實現原地分隔,將鏈表分成兩條鏈表(如果可能的話),其中一條鏈表的值都小於x,另一條鏈表的值都大於等於x。
爲了操作方便,可以引入啞結點,如果不想引入啞結點,也可以不引入。菜雞將給出兩種解答方式,供大家參考。
代碼實現
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
// 引入啞結點的解答方式
class Solution {
public ListNode partition(ListNode head, int x) {
// 特殊情況處理
if (head == null || head.next == null) return head;
// 設置啞結點
ListNode small = new ListNode(-1), sTmp = small;
ListNode big = new ListNode(-1), bTmp = big;
// 遍歷鏈表,並將鏈表以x爲界拆成兩條鏈表
while (head != null) {
if (head.val < x) {
sTmp.next = head;
sTmp = sTmp.next;
} else {
bTmp.next = head;
bTmp = bTmp.next;
}
head = head.next;
}
// 處理尾結點
bTmp.next = null;
// 合併兩條鏈表
sTmp.next = big.next;
// 返回結果
return small.next;
}
}
// 不引入啞結點的解答方式
class Solution {
public ListNode partition(ListNode head, int x) {
// 特殊情況處理
if (head == null || head.next == null) return head;
// 申請兩個變量作爲拆分鏈表的表頭
ListNode small = null, big = null;
// 申請兩個變量用於拆分鏈表的操作
ListNode sTmp = small, bTmp = big;
while (head != null) {
// 當前值小於x,並且表頭small爲空
if (head.val < x && small == null) {
small = head;
sTmp = head;
}
// 當前值大於等於x,並且表頭big爲空
else if (head.val >= x && big == null) {
big = head;
bTmp = head;
}
// 當前值小於x
else if (head.val < x) {
sTmp.next = head;
sTmp = sTmp.next;
}
// 當前值大於等於x
else {
bTmp.next = head;
bTmp = bTmp.next;
}
// 迭代
head = head.next;
}
// 如果大於等於x的鏈表不爲空,則設置尾結點指向null
if (bTmp != null) bTmp.next = null;
// 如果小於x的鏈表不爲空,則設置尾結點指向大於等於x鏈表的頭結點
if (sTmp != null) sTmp.next = big;
// 返回結果
return small != null ? small : big;
}
}
代碼分析
對代碼進行分析,無論是引入啞結點還是不引入啞結點,程序都對鏈表進行了一次遍歷,時間複雜度爲O(n);而就空間而言,兩種解決方式都只使用了常數級別的額外空間,空間複雜度爲O(1)。
執行結果
引入啞結點的執行結果
不引入啞結點的執行結果
基於leetcode的測試集,可以看出兩種方式的執行結果並無明顯區別。
學習 | 工作 | 分享
????長按關注“有理想的菜雞”
只有你想不到,沒有你學不到