没有思路时,将常用的数据结构和算法都想一遍
public class ListNode {
public int val;
public Node next;
Node(int x) {
val = x;
ext = null;//作用不大,写了更标准
}
}
先将一个链表元素存入map里,遍历第二个链表,看hash里面是否存在当前节点
public ListNode findFirstCommonNode(ListNode head1,ListNode head2){
Set set=new HashSet<>();
while(head1!=null){
set.add(head1);
head1=head1.next;
}
while(head2!=null){
if(set.contains(head2))
return head2;
head2=head2.next;
}
return null;
}
需要两个栈,出栈,如果相等就继续出栈,直到找到最晚出栈的一种。
需要两个O(n)的空间,面试不占优势。
java里Stack的peek方法是返回栈顶的元素但不移除它。
import java.util.Stack;
public ListNode findFirstCommonNode(ListNode head1,ListNode head2){
Stack stack1= new Stack();
Stack stack2= new Stack();
while(head1!=null){
stack1.push(head1);
head1=head1.next;
}
while(head2!=null){
stack2.push(head1);
head2=head2.next;
}
ListNode preNode=null;
while(stack1.size()>0 &&stack2.size()>0){
if(stack1.peek()==stack2.peek()){
preNode=stack1.pop();
stack2.pop();
}else break;
}
retun preNode;
}
两个链表A,B
A:1-2-3-4-5
B:a-b-4-5
AB:1-2-3-4-5-a-b-4-5
BA:a-b-4-5-1-2-3-4-5
分别遍历即可找到
public ListNode findFirstCommonNode(ListNode head1,ListNode head2){
if(head1==null||head2==null){
return null;
}
ListNode p1=head1;
ListNode p2=head2;
while(p1!=p2){//相同时退出循环
p1=p1.next;
p2=p2.next;
if(p1!=p2){
//一个链表访问完了跳转到另外一个链表上
if(p1==null) p1=head2;
if(p2==null) p2=head1;
}
}
return p1;
}
第一遍遍历,得到两个链表的长度L1,L2。
第二遍遍历,长的先走|L2-L1|,然后一起走,相同的就是公共节点
public ListNode findFirstCommonNode(ListNode head1,ListNode head2){
if(head1==null||head2==null){
return null;
}
ListNode p1=head1;
ListNode p2=head2;
int l1==0,l2=0;
//统计长度
while(p1!=null){
p1=p1.next;
l1++;
}
while(p2!=null){
p1=p2.next;
l2++;
}
p1=head1;
p2=head2;
//长的先走x步
if(l1>l2){
int a=0;
while(a
way1:
全部压栈,然后一边出栈一边比较。
public boolean isPalindrome(ListNode head){
ListNode temp=head;
Stack stack= new Stack();
while(temp!=null){
stack.push(temp.val);
temp=temp.next;
}
while(head!=null){
if(head.val!=stack.pop()) return false;
else head=head.next;
}
return true;
}
public ListNode mergeTwoLists(ListNode list1,ListNode list2){
ListNode newHead =new ListNode(-1);
ListNode res=newHead;
while(list1!=null && list2!=null){
if(list1.val
最终肯定只剩一个链表
public ListNode mergeTwoLists(ListNode list1,ListNode list2){
ListNode newHead =new ListNode(-1);
ListNode res=newHead;
while(list1!=null && list2!=null){
if(list1.val<=list2.val){
newHead.next=list1;
list1=list1.next;
}else{
newHead.next=list2;
list2=list2.next;
}
newHead=newHeas.next;
}
newHead.next=list1==null?list2:list1;
return res.next;
}
先将前两个合并再合并k个
public ListNode mergeLists(ListNode[] lists){
ListNode res=null;
for(ListNode list:lists)
res=mergeTwoLists(res,list);
return res;
}
使用快慢指针,fast一次走两步,slow一次走一步
public static ListNode middleNode(ListNode head){
ListNode slow=head,fast=head;
while(fast!=null && fast.next!=null){
slow=slow.next;
fast=fast.next.next;
}
return slow;
}
快慢指针问题,让fast和slow相隔k个节点,然后一起向后,当fast为null时,slow就在倒数第k个节点的位置
public static ListNode getKthFromEnd(ListNode head, int k){
ListNode slow=head,fast=head;
while(fast!=null && k>0){
fast=fast.next;
k--;
}
while(fast!=null){
fast=fast.next;
slow=slow.next;
}
return slow;
}
略
k有可能大于链表长度,取模。
快指针先走k步,然后一起往后走,,快指针到末尾的时候,慢指针指的位置刚好是要断开的位置。
public static ListNode rotateRight(ListNode head, int k){
if (head == null || k == 0) return head;
ListNode temp = head;
ListNode fast = head;
ListNode slow = head;
int len = 0;
while (head != null){
head=head.next;
len++;
}
if(k%len==0) return temp;
while((k%len)>0){
k--;
fast=fast.next;
}
while(fast.next!=null){
fast=fast.next;
slow=slow.next;
}
ListNode res=slow.next;
fast.next=temp;
solw.next=null;
return res;
}
创建虚拟表头dummyHead,其next指向Head。通过cur.next.val判断,通过cur.next=cur.next.next删除。最后返回dummyHead**.next.**
public static ListNode removeElements(ListNode head, int val){
ListNode dummyHead = new ListNode(0);
dummyHead.next = head;
ListNode cur=dummyHead;
while(cur.next!=null){
if(cur.next.val==val) cur.next=cur.next.next;
else cur=cur.next;
}
return dummyHead.next;
}
遍历得长度L,然后再遍历,在L-N+1处的元素是需要删除的
public static ListNode removeNthFromEndByLength(ListNode head, int n){
ListNode dummy = new ListNode(0);
dummy.next = head;
int length = getLength(head);//另外写的getLength函数
ListNode cur = dummy;
for (int i = 1; i < length - n + 1; ++i)
cur = cur.next;
cur.next = cur.next.next;
ListNode res = dummy.next;
return res;
}
找倒数第k,同上。
public static ListNode removeNthFromEnd(ListNode head, int n){
ListNode dummy = new ListNode(0);
dummy.next = head;
ListNode fast=head;
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;
ListNode res = dummy.next;
return res;
}
已知链表按升序排列,遍历即可
public static ListNode deleteDuplicate(ListNode head){
if(head==null) return head;
ListNode cur=head;
while(cur.next!=null){
if(cur.val==cur.next.val) cur.next=cur.next.next;
else cur=cur.next;
}
return head;
}
public static ListNode deleteDuplicate(ListNode head){
if(head==null) return head;
ListNode dummy = new ListNode(0,head);
ListNode cur=dummy;
while(cur.next!=null && cur.next.next!=null){
if(cur.next.val==cur.next.next.val) {
int x=cur.next.val;
while(cur.next!=null &&cur.next.val==x)
cur.next=cur.next.next;
}
else cur=cur.next;
}
return dummy.next;
}