leetcode第19题

简介: 上边我们遍历链表进行了两次,我们如何只遍历一次呢。看了 leetcode 的讲解。想象一下,两个人进行 100m 赛跑,假设他们的速度相同。开始的时候,第一个人就在第二个人前边 10m ,这样当第一个人跑到终点的时候,第二个人相距第一个人依旧是 10m ,也就是离终点 10m。对比于链表,我们设定两个指针,先让第一个指针遍历 n 步,然后再让它俩同时开始遍历,这样的话,当第一个指针到头的时候,第二个指针就离第一个指针有 n 的距离,所以第二个指针的位置就刚好是倒数第 n 个结点。

image.png

top19

给定一个链表,将倒数第 n 个结点删除。

解法一

删除一个结点,无非是遍历链表找到那个结点前边的结点,然后改变下指向就好了。但由于它是链表,它的长度我们并不知道,我们得先遍历一遍得到它的长度,之后用长度减去 n 就是要删除的结点的位置,然后遍历到结点的前一个位置就好了。

publicListNoderemoveNthFromEnd(ListNodehead, intn) {
intlen=0;
ListNodeh=head;
while (h!=null) {
h=h.next;
len++;
    }
//长度等于 1 ,再删除一个结点就为 null 了if (len==1) {
returnnull;
    }
intrm_node_index=len-n;
//如果删除的是头结点if (rm_node_index==0) {
returnhead.next;
    }
//找到被删除结点的前一个结点h=head;
for (inti=0; i<rm_node_index-1; i++) {
h=h.next;
    }
//改变指向h.next=h.next.next;
returnhead;
}

时间复杂度:假设链表长度是 L ,那么就第一个循环是 L 次,第二个循环是 L - n 次,总共 2L - n 次,所以时间复杂度就是 O(L)。

空间复杂度:O(1)。

我们看到如果长度等于 1 和删除头结点的时候需要单独判断,其实我们只需要在 head 前边加一个空节点,就可以避免单独判断。

publicListNoderemoveNthFromEnd(ListNodehead, intn) {
ListNodedummy=newListNode(0);
dummy.next=head;
intlength=0;
ListNodefirst=head;
while (first!=null) {
length++;
first=first.next;
    }
length-=n;
first=dummy;
while (length>0) {
length--;
first=first.next;
    }
first.next=first.next.next;
returndummy.next;
}

解法二 遍历一次链表

上边我们遍历链表进行了两次,我们如何只遍历一次呢。

看了 leetcode 的讲解。

想象一下,两个人进行 100m 赛跑,假设他们的速度相同。开始的时候,第一个人就在第二个人前边 10m ,这样当第一个人跑到终点的时候,第二个人相距第一个人依旧是 10m ,也就是离终点 10m。

对比于链表,我们设定两个指针,先让第一个指针遍历 n 步,然后再让它俩同时开始遍历,这样的话,当第一个指针到头的时候,第二个指针就离第一个指针有 n 的距离,所以第二个指针的位置就刚好是倒数第 n 个结点。

publicListNoderemoveNthFromEnd(ListNodehead, intn) {
ListNodedummy=newListNode(0);
dummy.next=head;
ListNodefirst=dummy;
ListNodesecond=dummy;
//第一个指针先移动 n 步for (inti=1; i<=n+1; i++) {
first=first.next;
    } 
//第一个指针到达终点停止遍历while (first!=null) {
first=first.next;
second=second.next;
    }
second.next=second.next.next;
returndummy.next;
}

时间复杂度:

第一个指针从 0 到 n ,然后「第一个指针再从 n 到结束」和「第二个指针从 0 到倒数第 n 个结点的位置」同时进行。

而解法一无非是先从 0 到 结束,然后从 0 到倒数第 n 个结点的位置。

所以其实它们语句执行的次数其实是一样的,从 0 到倒数第 n 个结点的位置都被遍历了 2 次,所以总共也是 2L - n 次。只不过这个解法把解法一的两次循环合并了一下,使得第二个指针看起来是顺便遍历,想法很 nice。

所以本质上,它们其实是一样的,时间复杂度依旧是 O(n)。

空间复杂度:O(1)。

利用两个指针先固定间隔,然后同时遍历,真的是很妙!另外室友的想法也很棒,哈哈哈哈哈

相关文章
|
4月前
|
C++ Python
leetcode-283:移动零
leetcode-283:移动零
26 0
|
4月前
LeetCode
LeetCode
32 0
|
4月前
leetcode-475:供暖器
leetcode-475:供暖器
37 0
|
4月前
|
消息中间件 Kubernetes NoSQL
LeetCode 1359、1360
LeetCode 1359、1360
|
测试技术
一和零(LeetCode-474)
一和零(LeetCode-474)
130 0
一和零(LeetCode-474)
leetcode第55题
当自己按照 45 题的思路写完的时候,看 Solution 的时候都懵逼了,这道题竟然这么复杂?不过 Solution 把问题抽象成动态规划的思想,以及优化的过程还是非常值得学习的。
leetcode第55题
|
算法
leetcode第42题
也就是红色区域中的水, 数组是 height = [ 0, 1, 0, 2, 1, 0, 1, 3, 2, 1, 2, 1 ] 。 原则是高度小于 2,temp ++,高度大于等于 2,ans = ans + temp,temp = 0。 temp 初始化为 0 ,ans 此时等于 2。 height [ 0 ] 等于 0 < 2,不更新。 height [ 1 ] 等于 1 < 2,不更新。 height [ 2 ] 等于 0 < 2, 不更新。 height [ 3 ] 等于 2 >= 2, 开始更新 height [ 4 ] 等于 1 < 2,temp = temp + 1 = 1。 h
leetcode第42题
|
算法
leetcode第47题
基本上都是在上道题的基础上改出来了,一些技巧也是经常遇到,比如先排序,然后判断和前一个是否重复。利用 Hash 去重的功能。利用原来的存储空间隐藏掉数据,然后再想办法还原。
leetcode第47题
leetcode第48题
将一个矩阵顺时针旋转 90 度,并且不使用额外的空间。大概属于找规律的题,没有什么一般的思路,观察就可以了。 解法一 可以先转置,然后把每列对称交换交换一下
leetcode第48题
leetcode第51题
较经典的回溯问题了,我们需要做的就是先在第一行放一个皇后,然后进入回溯,放下一行皇后的位置,一直走下去,如果已经放的皇后的数目等于 n 了,就加到最后的结果中。然后再回到上一行,变化皇后的位置,然后去找其他的解。 期间如果遇到当前行所有的位置都不能放皇后了,就再回到上一行,然后变化皇后的位置。再返回到下一行。 说起来可能还费力些,直接看代码吧。
leetcode第51题