Leetcode链表
Leetcode链表
一.闲聊
边学边刷的……慢慢写慢慢更
二.题目
1.移除链表元素
题干:
思路:
- 删除链表节点,就多了一个判断等值。
- 由于是单向链表,所以要删除节点时要找到目标节点的上一个节点,如果是双向链表,指向要删除节点本身即可
- 链表的头节点存在着被删除的风险,所以使用虚拟头节点来方便返回
代码:
public class ListNode{
int val;
ListNode next;
ListNode() {}
ListNode(int val) {this.val=val;}
ListNode(int val,ListNode next) {this.val=val;this.next=next;}
}
class Soulution{
public ListNode removeElements(ListNode head,int val){
//做个特判
if(head==null){
return head;
}
//以下两句可以用最后的构造器合并成一行。
ListNode dummy=new ListNode(0);
dummy.next=head;
ListNode cur=dummy;
while(cur.next!=null){
if(cur.next.val==val){
cur.next=cur.next.next
}else{
cur=cur.next;
}
}
return dummy.next;
}
}
2.设计链表
题干:
思路:
- 一步步顺着实现各个接口即可,长个心眼就是addAtIndex这个功能可以在特殊情况如Head和Tail中进行调用,没必要在两个方法重新编写了。、
代码:
class MyLinkedList {
int size;
ListNode head;
public MyLinkedList() {
size=0;
head=new ListNode(0);
}
public int get(int index) {
if(index<0||index>=size){
return -1;
}
ListNode cur=head;
for(int i=0;i<=index;i++){
cur=cur.next;
}
return cur.val;
}
public void addAtHead(int val) {
addAtIndex(0,val);
}
public void addAtTail(int val) {
addAtIndex(size,val);
}
public void addAtIndex(int index, int val) {
if(index<0){
index=0;
}
if(index>size){
return;
}
size++;
ListNode listNode=new ListNode(val);
ListNode cur=head;
for(int i=0;i<index;i++){
cur=cur.next;
}
listNode.next=cur.next;
cur.next=listNode;
}
public void deleteAtIndex(int index) {
if(index>=size||index<0){
return;
}
size--;
ListNode cur=head;
for(int i=0;i<index;i++){
cur=cur.next;
}
cur.next=cur.next.next;
}
}
class ListNode{
int val;
ListNode next;
ListNode(){}
ListNode(int val){
this.val=val;
}
}
这道题用了虚拟头节点,也可以理解为哨兵,目的是为了保证链表始终处于非空的状态。 而正由于存在虚拟头节点,所以与传统的链表操作存在不同,但思想一致。比如查找节点的值时,如果不存在虚拟头节点,那么我们循环index次即可,现在要循环index+1
次。
3.翻转链表
题干:反转一个单链表。 示例:示例: 输入: 1->2->3->4->5->NULL 输出: 5->4->3->2->1->NULL
思路:
- 双指针法即可。一前一后配合
代码:
class Solution {
public ListNode reverseList(ListNode head) {
ListNode cur=head;
ListNode pre=null;
while (cur!=null){
//将下一个节点保存,否则就找不到下一个了
ListNode temp=cur.next;
cur.next=pre;
pre=cur;
cur=temp;
}
return pre;
}
}
4.删除链表的倒数第N个节点
题干:
思路:
- 双指针,一快一慢,快的先走
n+1
步,保证慢指针最后会指向要删除节点的前一个节点,之后执行普通的删除节点操作即可 - 这题同样存在着删除头结点的情况,所以使用虚拟头节点方便处理
代码:
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode dummy=new ListNode(0);
dummy.next=head;
ListNode fast=dummy;
ListNode slow=dummy;
for(int i=0;i<=n;i++){
fast=fast.next;
}
while (fast!=null){
fast=fast.next;
slow=slow.next;
}
slow.next=slow.next.next;
return dummy.next;
}
}
5.链表相交
题干:
思路:
- 首先遍历第一个链表,其中会产生重复的部分必定不是两链表的相交点,所以可以利用哈希集合去重,并记录下每个节点。之后遍历第二条链表的同时在哈希集合中查找是否存在交集,存在的第一个交集即是链表的交点,之后的所有点都是共同点。
代码:
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
Set<ListNode> set=new HashSet<ListNode>();
while (headA!=null){
set.add(headA);
headA=headA.next;
}
while (headB!=null){
if(set.contains(headB)){
return headB;
}
headB=headB.next;
}
return null;
}
}
6.环形链表II
题干:
思路:
- 与链表相交题目相似,一种解法是同样可以利用哈希集合判断,遍历链表,当出现当前节点的下一节点已经存在于哈希集合当中时,我们就返回当前节点下一节点即可(也可以是当前节点出现在哈希集合中后,返回当前节点)
代码:
public class Solution {
public ListNode detectCycle(ListNode head) {
Set<ListNode> set=new HashSet<ListNode>();
ListNode cur=head;
while (cur!=null){
if(set.contains(cur)){
return cur;
}else{
set.add(cur);
}
cur=cur.next;
}
return null;
}
}