这篇博客就是总结以下自己刷力扣链表简单题的错误点与想法。
目录
1.合并两个有序链表
第一次的有错想法:
class Solution {
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
ListNode dummy = new ListNode(-1);
ListNode tmp = dummy;
while (l1 != null || l2 != null){
if (l1.val > l2.val){
tmp.next = l2;
l2 = l2.next;
tmp = tmp.next;
}else{
tmp.next = l1;
l1 = l1.next;
tmp = tmp.next;
}
}
if (l1 == null){
tmp.next = l2;
}else if (l2 == null){
tmp.next = l1;
}
return dummy.next;
}
}
但是报错了,空指针异常。
结果这里是 '||' 和 '&&' 符号出的问题
'||' 左右必须都是假,才会退出
'&&' 左右只要有一个为假,就会退出
如果写的是 ‘while (l1 != null || l2 != null)’,那么两个都不是null才会退出
所以改成 ‘&&' 才能保证有一个不是就退出,以保证下面代码正常。
2.删除链表中的重复元素
第一次的有错想法:
class Solution {
public ListNode deleteDuplicates(ListNode head) {
ListNode cur = head;
while (cur != null){
if (cur.next != null && cur.val == cur.next.val){
cur.next = cur.next.next;
}
cur = cur.next;
}
return head;
}
}
示例没错,但败在这个例子上:
说明这里还是有逻辑错误的,来理一下
如果cur的值与cur.next的值相等,直接掠过cur.next值,然后让cur到下一个节点
这样确实能去掉两个连续的值,但是如果是三个连续乃至更多的值呢?
掠过一个重复的值就让 cur 到下一个结点显然有点急
所以很简单,掠过一个重复值,不要急着移动cur,如果不是重复的再移动cur也不急
正确代码:
class Solution {
public ListNode deleteDuplicates(ListNode head) {
ListNode cur = head;
while (cur != null){
if (cur.next != null && cur.val == cur.next.val){
cur.next = cur.next.next;
}else{
cur = cur.next;
}
}
return head;
}
}
3.删除链表中的特定节点
接下来把删除节点的题都做一下
此题要注意,不能用head访问,且删除的节点不是末尾节点
让你原地删除
既然不能用head,就从val就下手
复制一份val,然后把原val略过去就好了。
class Solution {
public void deleteNode(ListNode node) {
node.val = node.next.val;
node.next = node.next.next;
}
}
4.移除链表元素
第一次的错误想法:
class Solution {
public ListNode removeElements(ListNode head, int val) {
if (head == null){
return null;
}
ListNode cur = head;
while (cur != null){
if (cur.next != null && cur.next.val == val){
cur.next = cur.next.next;
}else {
cur = cur.next;
}
}
return head;
}
}
示例正确,但是有特例:
这种全都是一个数字的情况就特殊
这种情况可以直接从头节点遍历,如果是val,就略过。
正确代码:
class Solution {
public ListNode removeElements(ListNode head, int val) {
if (head == null){
return null;
}
while (head != null && head.val == val){
head = head.next;
}
ListNode cur = head;
while (cur != null){
if (cur.next != null && cur.next.val == val){
cur.next = cur.next.next;
}else {
cur = cur.next;
}
}
return head;
}
}
当然,标准答案里也用了傀儡节点来规避上面的问题,这里也列出:
class Solution {
public ListNode removeElements(ListNode head, int val) {
ListNode dummyHead = new ListNode(0);
dummyHead.next = head;
ListNode temp = dummyHead;
while (temp.next != null) {
if (temp.next.val == val) {
temp.next = temp.next.next;
} else {
temp = temp.next;
}
}
return dummyHead.next;
}
}
5.环形链表
这题运用了快慢指针的思想
如果两指针在往后走的时候相等,那么就有环
如果走到null了也没相等,那么没环
看下面代码:
public class Solution {
public boolean hasCycle(ListNode head) {
if (head == null){
return true;
}
ListNode fast = head;
ListNode slow = head;
while (fast != null){
fast = fast.next.next;
slow = slow.next;
if (fast == slow){
return true;
}
}
return false;
}
}
有如下的异常:
因为这里访问到了next.next
所以要防止fast.next是null,访问空指针的异常
正确代码:
public class Solution {
public boolean hasCycle(ListNode head) {
if (head == null){
return false;
}
ListNode fast = head;
ListNode slow = head;
while (fast != null && fast.next != null){
fast = fast.next.next;
slow = slow.next;
if (fast == slow){
return true;
}
}
return false;
}
}