从尾到头打印链表
blic ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
ArrayList<Integer>list=new ArrayList<>();
if(listNode==null)return list;
while(listNode!=null){
list.add(0,listNode.val);
listNode=listNode.next;
}
return list;
}
链表中倒数第k个结点
先走k步,如果中途为空,说明链表长度小于k,则返回null
public ListNode FindKthToTail(ListNode head,int k) {
if(head==null)
return null;
ListNode a=head;
ListNode b=head;
for(int i=0;i<k;i++){
if(a!=null){
a=a.next;
}else{
return null;
}
}
while(a!=null){
b=b.next;
a=a.next;
}
return b;
}
反转链表
public ListNode ReverseList(ListNode head) {
if(head==null)return null;
ListNode pre=head;
ListNode result=null;
while(pre!=null){
ListNode next=pre.next;
pre.next=result;
result=pre;
pre=next;
}
return result;
}
合并两个排序的链表
public ListNode Merge(ListNode list1,ListNode list2) {
if(list1==null)return list2;
if(list2==null)return list1;
ListNode node=new ListNode(0);
ListNode result=node;
ListNode pre1=list1;
ListNode pre2=list2;
while(pre1!=null&&pre2!=null){
if(pre1.val<=pre2.val){
result.next=pre1;
result=pre1;
pre1=pre1.next;
}else{
result.next=pre2;
result=pre2;
pre2=pre2.next;
}
}
if(pre1!=null)result.next=pre1;
if(pre2!=null)result.next=pre2;
return node.next;
}
删除链表的重复结点
用三个指针遍历
public ListNode deleteDuplication(ListNode pHead)
{
if(pHead==null)return null;
ListNode node=new ListNode(0);
node.next=pHead;
ListNode pre1=node;
ListNode pre2=pHead;
ListNode pre3=pHead.next;
while(pre3!=null){
if(pre2.val!=pre3.val){
pre1=pre1.next;
pre2=pre2.next;
pre3=pre3.next;
}else{
while(pre3!=null&&pre2.val==pre3.val){
pre3=pre3.next;
}
pre1.next=pre3;
pre2=pre3;
if(pre3!=null){
pre3=pre3.next;
}
}
}
return node.next;
}
链表中环的入口结点
- 判断链表是否带环,用快慢指针,如果相遇说明有环。
- 一个指针从头开始,一个从相遇结点开始,直到它们两相遇,就是环的入口结点
public ListNode EntryNodeOfLoop(ListNode pHead)
{
if(pHead==null)return null;
ListNode p1=pHead;
ListNode p2=pHead;
do{
p1=p1.next;
if(p1==null)
return null;
p1=p1.next;
p2=p2.next;
}while(p1!=p2);
ListNode p3=pHead;
while(p1!=p3){
p1=p1.next;
p3=p3.next;
}
return p3;
}
两个链表的第一个公共结点
思路一:求出两个链表的长度,找出长的链表,让长的链表走长度差,再让两个一起走,直到相遇。
public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) {
if(pHead1==null)return null;
if(pHead2==null)return null;
ListNode p1=pHead1;
ListNode p2=pHead2;
int len1=getLength(pHead1);
int len2=getLength(pHead2);
int k=0;
if(len1<len2){
p1=pHead2;
p2=pHead1;
k=len2-len1;
}
k=len1-len2;
for(int i=0;i<k;i++){
p1=p1.next;
}
while(p1!=p2){
p1=p1.next;
p2=p2.next;
}
return p2;
}
public static int getLength(ListNode phead){
if(phead==null)return 0;
int count=0;
ListNode p=phead;
while(p!=null){
count++;
p=p.next;
}
return count;
}
思路二:相当于遍历一遍两个链表的长度和即可
例如:
l1:0-1-2-3-4-5-null
l2:a-b-4-5-null
p1: 0-1-2-3-4-5-null(此时遇到ifelse)-a-b-4-5-null
p2: a-b-4-5-null(此时遇到ifelse)0-1-2-3-4-5-null
因此,两个指针所要遍历的链表就长度一样了!
public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) {
if(pHead1==null)return null;
if(pHead2==null)return null;
ListNode p1=pHead1;
ListNode p2=pHead2;
while(p1!=p2){
p1=p1==null?pHead2:p1.next;
p2=p2==null?pHead1:p2.next;
}
return p1;
}
二叉搜索树与双向链表
用的是中序遍历非递归版本
public TreeNode Convert(TreeNode pRootOfTree) {
if(pRootOfTree==null)return null;
Stack<TreeNode>stack=new Stack<>();
TreeNode pre=pRootOfTree;
TreeNode node=null;
boolean bool=true;
while(!stack.isEmpty()||pre!=null){
while(pre!=null){
stack.push(pre);
pre=pre.left;
}
TreeNode top=stack.pop();
if(bool){
pRootOfTree=top;//让第一个结点作为头
node=top;
bool=false;
}else{
node.right=top;
top.left=node;
node=top;
}
pre=top.right;
}
return pRootOfTree;
}
复杂链表的复制
public RandomListNode Clone(RandomListNode pHead)
{
if(pHead==null)return null;
RandomListNode node=pHead;
//合并
while(node!=null){
RandomListNode a=new RandomListNode(node.label);
a.random=null;
a.next=node.next;
node.next=a;
node=a.next;
}
//算random
RandomListNode pre1=pHead;
while(pre1!=null){
RandomListNode pre2=pre1.next;
if(pre1.random!=null){
pre2.random=pre1.random.next;
}
pre1=pre2.next;
}
//拆分
pre1=pHead;
RandomListNode result=pHead.next;
while(pre1!=null){
RandomListNode p=pre1.next;
pre1.next=p.next;
if(p.next!=null){
p.next=p.next.next;
}
pre1=pre1.next;
}
return result;
}
重排链表
方法一:找到中间结点,将尾部链表逆置,然后遍历两个链表,交叉插入结点。
方法二:将结点放入到队列中,方便取两边的结点。注意最后要设置空结点。
public void reorderList(ListNode head) {
LinkedList<ListNode>queue=new LinkedList<>();
if(head==null)return;
ListNode pre=head;
while(pre!=null){
queue.addLast(pre);
pre=pre.next;
}
while(!queue.isEmpty()){
if(pre==null){
pre=queue.pollFirst();
}else{
pre.next=queue.pollFirst();
pre=pre.next;
}
pre.next=queue.pollLast();
pre=pre.next;
}
if(pre!=null)
pre.next=null;
}
分割链表
将小于x的放在一个链表中,大于等于x的放到另外链表中,链表尾插比较麻烦,所以添加一个0元素的结点就不用每次去判断头结点为不为空。左后合并链表的时候,分为三中情况。
public ListNode partition(ListNode head, int x) {
if(head==null)return null;
ListNode head1=new ListNode(0);
ListNode p1=head1;
ListNode head2=new ListNode(0);
ListNode p2=head2;
ListNode pre=head;
while(pre!=null){
if(pre.val<x){
p1.next=pre;
p1=p1.next;
pre=pre.next;
}else{
p2.next=pre;
p2=p2.next;
pre=pre.next;
}
}
if(p1==null)return head2.next;
else if(p2==null)return head1.next;
else{
p1.next=head2.next;
p2.next=null;
}
return head1.next;
}
链表求和
思想:遍历两个链表,carry用来存进位,每次算出一个数就添加一个新的结点,最后好需要判断下carry是不是为0,不为0还要再添加一个结点。
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
if(l1==null)return l2;
if(l2==null)return l1;
ListNode result=new ListNode(0);
ListNode res=result;
int carry=0;
while(l1!=null||l2!=null){
int num1=l1==null?0:l1.val;
int num2=l2==null?0:l2.val;
int sum=num1+num2+carry;
carry=sum/10;
res.next=new ListNode(sum%10);
res=res.next;
l1=l1==null?null:l1.next;
l2=l2==null?null:l2.next;
}
if(carry>0){
res.next=new ListNode(carry);
}
return result.next;
}
旋转链表
思路:首先算出链表的长度,计算出要循环的次数,也就是length-(k%length),然后将链表变成循环链表,一个从尾指针开始,一个从头指针开始,遍历次数完成,将尾指针的next设为null,返回头指针现在所在的位置,就是头结点。
public ListNode rotateRight(ListNode head, int k) {
if(head==null||k==0)return head;
int length=1;
ListNode p1=head;
while(p1.next!=null){
p1=p1.next;
length++;
}
int top=length-(k%length);
ListNode p2=head;
//构建环形链表 p1是尾指针,p2是头指针
p1.next=head;
for(int i=0;i<top;i++){
p1=p1.next;
p2=p2.next;
}
p1.next=null;
return p2;
}
奇偶链表
public ListNode oddEvenList(ListNode head) {
if(head==null)return head;
ListNode o=head;//head为奇链表的头结点,o为奇链表的尾结点
ListNode p=head.next;//偶链表的头结点
ListNode e=head.next;//偶链表的尾结点
while(o.next!=null&&e.next!=null){
o.next=e.next;
o=o.next;
e.next=o.next;
e=e.next;
}
o.next=p;
return head;
}
移除链表元素
有可能链表只有一个结点,并且这个结点值就是val,有可能val再结尾会出现,所以方便减少代码判断,先设置一个0的结点放在head的前面。这样就不用考虑特殊情况了。
public ListNode removeElements(ListNode head, int val) {
if(head==null)return head;
ListNode node=new ListNode(0);
node.next=head;
ListNode pre=node;
while(pre.next!=null){
if(pre.next.val!=val){
pre=pre.next;}
else
pre.next=pre.next.next;
}
// if(pre.val==val)
// pre.next=null;
return node.next;
}
删除链表中的结点
比如3–4--5,需要删除4,让4这个结点值为5,再绕过5这个结点即可。
public void deleteNode(ListNode node) {
node.val=node.next.val;
node.next=node.next.next;
}
两两交换链表中的结点
三个指针进行交换
public ListNode swapPairs(ListNode head) {
if(head==null||head.next==null)return head;
ListNode node=new ListNode(0);
ListNode p1=node;
node.next=head;
while(head!=null&&head.next!=null){
ListNode p2=head;
ListNode p3=head.next;
p1.next=p3;
p2.next=p3.next;
p3.next=p2;
p1=p2;
head=p2.next;
}
return node.next;
}
链表的中间结点
public ListNode middleNode(ListNode head) {
ListNode a=head;
ListNode b=head;
while(a!=null&&a.next!=null){
a=a.next.next;
b=b.next;
}
return b;
}
k个一组反转链表
public ListNode reverseKGroup(ListNode head, int k) {
ListNode node=new ListNode(0),prev=node,next,curry=head;
int length=0;
while(curry!=null){
length++;
curry=curry.next;
}
curry=head;
node.next=head;
for(int i=0;i<length/k;i++){
for(int j=0;j<k-1;j++){
next=curry.next;
curry.next=next.next;
next.next=prev.next;
prev.next=next;
}
prev=curry;
curry=curry.next;
}
return node.next;
}
合并k个排序链表
public ListNode mergeKLists(ListNode[] lists) {
if(lists.length==0)return null;
if(lists.length==1)return lists[0];
if(lists.length==2) return mergeTwo(lists[0],lists[1]);
int mid=lists.length/2;
ListNode[]l1=new ListNode[mid];
ListNode[]l2=new ListNode[lists.length-mid];
for(int i=0;i<mid;i++){
l1[i]=lists[i];
}
for(int j=0,i=mid;i<lists.length;j++,i++){
l2[j]=lists[i];
}
return mergeTwo(mergeKLists(l1),mergeKLists(l2));
}
private ListNode mergeTwo(ListNode p, ListNode q) {
if(p==null)return q;
if(q==null)return p;
ListNode result=new ListNode(-1);
ListNode res=result;
while(p!=null&&q!=null){
if(p.val<=q.val){
result.next=new ListNode(p.val);
result=result.next;
p=p.next;
}else{
result.next=new ListNode(q.val);
result=result.next;
q=q.next;
}
}
if(p!=null)result.next=p;
if(q!=null)result.next=q;
return res.next;
}