public ListNode removeElements(ListNode head, int val) {
//该题使用双指针,pre指向待删除结点的前驱,cur指向待删除结点
//引入虚拟头结点,解决头结点无前驱问题
ListNode dummyHead = new ListNode();
dummyHead.next = head;
ListNode pre = dummyHead;
ListNode cur = head;
//cur == null时已经遍历完整个链表,结束循环
while (cur != null){
//找到待删结点时
if (cur.val == val){
//pre的下一个结点指向cur的下一个结点,以此删除当前结点结点
pre.next = cur.next;
//cur后移,继续判断
cur = pre.next;
}else {
//cur所在的结点不是待删结点时,两个指针同时后移
pre = pre.next;
cur = cur.next;
}
}
return dummyHead.next;
}
public ListNode removeElements(ListNode head, int val) {
//边界条件
//当链表中没有结点时,不用删除
if (head == null){
return null;
}
//把链表拆分为头结点和剩下的结点
//剩下的结点交给removeElements()处理
head.next = removeElements(head.next,val);
//判断头结点是否为待删除结点
if (head.val == val){
return head.next;
}
else {
return head;
}
}
leetcode82 删除排序链表中的重复元素
法一:普通迭代
此时需要用到三指针,pre指向待删结点的结点,cur和next用来判断是否出现重复元素,next指向第一个不重复的结点。
public ListNode deleteDuplicates(ListNode head) {
ListNode dummyHead = new ListNode();
dummyHead.next = head;
ListNode pre = dummyHead;
ListNode cur = head;
//循环开始的条件是链表中至少有两个结点,并且需要保证cur.next和next.val不会出现空指针异常
while (cur != null && cur.next != null){
//next总是指向cur的后一个结点,我们将其定义在循环内
ListNode next = cur.next;
//当没有遇到重复元素时,三个指针同时后移
if (cur.val != next.val){
pre = pre.next;
cur = cur.next;
}else {
//当找到重复元素时,我们让next一直后移判断,知道next指向第一个不与cur相等的结点
//此时我们也要确保不会出现空指针异常
while (next != null && cur.val == next.val){
next = next.next;
}
//删除所有重复的结点
pre.next = next;
cur = next;
}
}
return dummyHead.next;
}
public ListNode deleteDuplicates(ListNode head) {
//边界
if (head == null || head.next == null){
return head;
}
//首先判断头结点是否为重复结点
//头结点不是重复结点时,head.next交给deleteDuplicates(ListNode head.next)处理
//返回头结点
if (head.val != head.next.val) {
head.next = deleteDuplicates(head.next);
return head;
} else {
//头结点是重复节点时
//头结点后移,直到头结点的下一个结点不是重复节点
//head.next交给deleteDuplicates(ListNode head.next)处理
//返回head.next
while (head.next != null && head.val == head.next.val){
head = head.next;
}
head.next = deleteDuplicates(head.next);
return head.next;
}
}
leetcode206 反转链表
法一:创建新链表,头插原来链表中的元素
public ListNode reverseList(ListNode head) {
//法一:创建新链表,头插原来链表中的元素
ListNode dummyHead = new ListNode();
while (head != null){
ListNode node = new ListNode(head.val,dummyHead.next);
dummyHead.next = node;
head = head.next;
}
return dummyHead.next;
}
public ListNode reverseList(ListNode head) {
ListNode pre = null;
ListNode cur = head;
while (cur != null){
//暂存cur的下一个结点
ListNode next = cur.next;
//改变cur的指向方向
cur.next = pre;
pre = cur;
cur = next;
}
return pre;
}
public ListNode reverseList(ListNode head) {
//边界
if (head == null || head.next == null){
return head;
}
//node指向反转后的尾结点
ListNode node = head.next;
ListNode newHead = reverseList(head.next);
head.next = null;
node.next = head;
return newHead;
}
leetcode876 链表的中间结点
法一:遍历整个链表,找到中间结点
public ListNode middleNode(ListNode head) {
//遍历链表,count记录链表的结点个数
int count = 0;
for (ListNode x = head;x != null;x = x.next){
count++;
}
//middle是中间结点的索引
int middle = count / 2;
ListNode node = head;
//node走middle步到达中间结点
for (int i = 0; i < middle; i++) {
node = node.next;
}
return node;
}
法二:快慢指针,走相同的路程,fast的速度是slow的两倍,即fast走两步,slow走一步,当fast走到终点时,slow正好走到中间位置。
//快慢指针
public ListNode middleNode(ListNode head) {
ListNode fast = head;
ListNode slow = head;
while (fast != null && fast.next != null){
fast = fast.next.next;
slow = slow.next;
}
return slow;
}
public ListNode getKthFromEnd(ListNode head, int k) {
//判断链表是否为空和k的合法性
if (head == null || k <= 0){
return null;
}
ListNode fir = head;
ListNode sec = head;
int count = 0;
//fir比sec多走k步
for (int i = 0; i < k; i++) {
fir = fir.next;
count++;
}
//k超出链表范围
if (count < k){
return null;
}
while (fir != null){
fir = fir.next;
sec = sec.next;
}
return sec;
}
public ListNode mergeTwoLists(ListNode list1, ListNode list2) {
//判空
if (list1 == null){
return list2;
}
if (list2 == null){
return list1;
}
ListNode dummyHead = new ListNode();
ListNode node = dummyHead;
while (list1 != null && list2 != null){
//不断去寻找两个链表中较小的结点,将其连接到尾部
if (list1.val <= list2.val){
node.next = list1;
node = node.next;
list1 = list1.next;
}else {
node.next = list2;
node = node.next;
list2 = list2.next;
}
}
//当list1和list2有一个为空时,跳出循环
//若list1为空,则链表尾部连接上list2剩余的结点
if (list1 == null){
node.next = list2;
//反之,链表尾部连接上list1剩余的结点
}else {
node.next = list1;
}
return dummyHead.next;
}
分割链表
创建两个新链表,一个存放原链表中小于x的结点,一个存放原链表中大于等于x的结点。
public ListNode partition(ListNode head, int x) {
if (head == null || head.next == null){
return head;
}
//创建两个链表,一个存储小于x的节点,一个存储大于等于x的节点
ListNode dummyHead1 = new ListNode();
ListNode node1 = dummyHead1;
ListNode dummyHead2 = new ListNode();
ListNode node2 = dummyHead2;
while (head != null){
//node1存储小于x的节点
if (head.val < x){
node1.next = head;
node1 = node1.next;
head = head.next;
}else {
//node2存储大于等于x的节点
node2.next = head;
node2 = node2.next;
head = head.next;
}
}
//断开node2后面小于x的节点
node2.next = null;
//连接node1和node2
node1.next = dummyHead2.next;
return dummyHead1.next;
}