2021-6-13-剑指笔记01
Posted 轻舟一曲
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2021-6-13-剑指笔记01相关的知识,希望对你有一定的参考价值。
笔记01
_11_返回倒数第k个节点
package LeetCode._面试经典.笔记01;
public class _11_返回倒数第k个节点 {
public class ListNode {
int val;
ListNode next;
ListNode(int x) { val = x; }
}
/*
1.递归:代码简洁但是需要占用O(N)的空间
2.迭代:代码稍微复杂一点但是效率快
* */
public int K=0;
public int value=0;
public int kthToLast(ListNode head, int k) {
K=k;
nthToLast(head);
return value;
}
//递归每次返回该节点的下标(tip:最后1个为倒数第1个)
public int nthToLast(ListNode node){
if (node==null) return 0;
int l=nthToLast(node.next)+1;
if (l==K) value=node.val;
return l;
}
//快慢指针
public int kthToLast02(ListNode head, int k) {
if (head==null) return 0;
ListNode slow=head;
ListNode fast=head;
while (k>0&&fast!=null){//最后fast肯定到null所以需要多走1步
fast=fast.next;
k--;
}
if (k!=0) return 0;//不合法的k
while (fast!=null){
slow=slow.next;
fast=fast.next;
}
return slow.val;
}
}
_12_删除链表中间节点
package LeetCode._面试经典.笔记01;
import org.junit.Test;
import java.util.Random;
public class _12_删除链表中间节点 {
public class ListNode {
int val;
ListNode next;
ListNode(int x) { val = x; }
}
/*
中间节点:除去首尾节点外都叫中间节点,只能访问删除的的节点
tips:若待删除的是尾结点,该题无解,面试的时候应该给面试官指出
将其为null ? 很明显这就是对指针的不理解了,你置null只是将node置null,却并未将前驱节点的next置null,其还是只想该块内存额
* */
public void deleteNode(ListNode node) {
if (node==null) return;
if (node.next==null) {
System.out.println("尾结点:"+node.val);
node.val=-1;
return;
}
node.val=node.next.val;
node.next=node.next.next;
}
@Test
public void test(){
//[a,b] random(b-a)+a
ListNode head=new ListNode(1);
ListNode n2=new ListNode(2);
ListNode n3=new ListNode(3);
ListNode n4=new ListNode(4);
head.next=n2;
n2.next=n3;
n3.next=n4;
deleteNode(n4);
print(head);
}
public void print(ListNode node){
ListNode p=node;
while (p!=null){
System.out.println(p.val);
p=p.next;
}
}
}
_13_分割链表
package LeetCode._面试经典.笔记01;
import org.junit.Test;
public class _13_分割链表 {
public class ListNode {
int val;
ListNode next;
ListNode(int x) { val = x; }
}
/*
询问如果不考虑"稳定性":原来的顺序不变-->1个链表:头插+尾插
考虑:2个链表
* */
public ListNode partition01(ListNode head, int x) {
if (head==null) return null;
ListNode lowS=new ListNode(-1);
ListNode lowL=lowS;
ListNode highS=new ListNode(-1);
ListNode highL=highS;
ListNode p=head;
while (p!=null){//保证losS或highS最后1个不为null
if (p.val<x){
lowL.next=p;
lowL=lowL.next;
}
else {
highL.next=p;
highL=highL.next;
}
p=p.next;
}
//避免出现环
lowL.next=null;
highL.next=null;
lowL.next=highS.next;
return lowS.next;
}
//不考虑稳定性,利用现有节点进行头插尾插法,更简洁代码
//左边部分<x 右边部分>=x
public ListNode partition(ListNode head, int x){
if (head==null) return null;
ListNode S=head;
ListNode L=head;
ListNode P=head.next;
while (P!=null){
ListNode next=P.next;
if (P.val<x){
P.next=S;//p.next断开,下面就用不到了
S=P;
}
else {
L.next=P;
L=P;
}
P=next;
}
L.next=null;
return S;
}
@Test
public void test(){
ListNode n1=new ListNode(1);
ListNode n2=new ListNode(4);
ListNode n3=new ListNode(3);
ListNode n4=new ListNode(2);
ListNode n5=new ListNode(5);
ListNode n6=new ListNode(2);
n1.next=n2;
n2.next=n3;
n3.next=n4;
n4.next=n5;
n5.next=n6;
ListNode res=partition(n1,3);
}
}
_14_链表求和
package LeetCode._面试经典.笔记01;
public class _14_链表求和 {
public class ListNode {
int val;
ListNode next;
ListNode(int x) { val = x; }
}
/*
首先回顾一下加法:
6 1 7
+ 2 5 9
可用递归实现,注意短链表的空指针
* */
public ListNode addTwoNumbers01(ListNode l1, ListNode l2) {
return nextList(l1,l2,0);
}
public ListNode nextList(ListNode l1,ListNode l2,int carry){
if (l1==null&&l2==null&&carry==0) return null;
int sum=carry;
if (l1!=null) sum+=l1.val;
if (l2!=null) sum+=l2.val;
ListNode res=new ListNode(sum%10);//先序遍历
res.next=nextList(l1==null?null:l1.next,l2==null?null:l2.next,sum/10);
return res;
}
/*
进阶:整数正向存储
因为需要配对,所以需要先补0
* */
public class PartialSum{//封装类
public ListNode sum=null;
public int carry=0;
}
//两个节点相加得到一个封装加数节点PartialSum,再往前传递即可
PartialSum addHelper(ListNode l1,ListNode l2){
if (l1==null&&l2==null){
return new PartialSum();
}
PartialSum sumHelper=addHelper(l1.next,l2.next);
//得到l1.next,l2.next的加数类,直接拿加数类的节点即可
//构造当前加数类的节点
int val=sumHelper.carry+l1.val+l2.val;
ListNode node=new ListNode(val%10);//当前加数节点
if (sumHelper.sum!=null)
node.next=sumHelper.sum;
sumHelper.carry=val/10;
return sumHelper;//最后返回的是一个加数节点和进位
}
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
if (l1==null||l2==null) return l1==null?l2:l1;
int count1=0;
ListNode p1=l1;
while (p1!=null){
count1++;
p1= p1.next;
}
int count2=0;
ListNode p2=l1;
while (p2!=null){
count2++;
p2= p2.next;
}
if (count1<count2) return addTwoNumbers(l2,l2);
//保证l1最长
int diff=count1-count2;
ListNode head2=new ListNode(0);
ListNode p=head2;
for (int i=1;i<=diff;i++){
ListNode node=new ListNode(0);
p.next=node;
p=node;
}
if (diff!=0){
p.next=l2;
l2=head2;
}
PartialSum res=addHelper(l1,l2);
if (res.carry==0)
return res.sum;
else {
ListNode node=new ListNode(res.carry);//当前加数节点
if (res.sum!=null)
node.next=res.sum;
return node;
}
}
}
_15_回文链表
编写一个函数,检查输入的链表是否是回文的。
示例 1:
输入: 1->2
输出: false
示例 2:
输入: 1->2->2->1
输出: true
进阶:
你能否用 O(n) 时间复杂度和 O(1) 空间复杂度解决此题?
package LeetCode._面试经典.笔记01;
import org.junit.Test;
import java.util.ArrayDeque;
public class _15_回文链表 {
public class ListNode {
int val;
ListNode next;
ListNode(int x) { val = x; }
}
//方法1:先将链表反转(头插),然后比较前半部分 O(N) O(N)
public boolean isPalindrome01(ListNode head) {
if (head==null) return true;
ListNode node=getReverse(head);
return isReverse(head,node);
}
public ListNode getReverse(ListNode head){
ListNode p=head;
ListNode r=null;
while (p!=null){
ListNode node=new ListNode(p.val);
node.next=r;
r=node;
p=p.next;
}
//最后一个节点为头节点
return r;
}
public boolean isReverse(ListNode l1,ListNode l2){
ListNode p1=l1;
ListNode p2=l2;
while (p1!=null&&p2!=null){
if (p1.val!=p2.val) return false;
p1=p1.next;
p2=p2.next;
}
return true;
}
//---------------------------------------------------------------
//方法2:迭代法,利用栈+快慢指针 O(N) O(N)
public boolean isPalindrome02(ListNode head) {
if (head==null) return true;
ListNode slow=head;
ListNode fast=head;
ArrayDeque<Integer> deque = new ArrayDeque<>();
while (fast!=null&&fast.next!=null){
deque.addFirst(slow.val);
slow=slow.next;
fast=fast.next.next;
}
//因为有奇数个节点,所以跳过中间节点
if (fast!=null) slow=slow.next;
while (slow!=null){
if (deque.removeFirst()!=slow.val) return false;
slow=slow.next;
}
return true;
}
//---------------------------------------------------------------
//方法3:递归,使用一个封装类
class Result{
ListNode node;
boolean result;
public Result(ListNode node, boolean result) {
this.node = node;
this.result = result;
}
}
public boolean isPalindrome(ListNode head){
int len=0;
ListNode p=head;
while (p!=null){
len++;
p=p.next;
}
Result reverse = isReverse(head, len);
return reverse.result;
}
//封装类的意思是返回 内序列的比对结果以及下次比较的内序列的最后1个节点
Result isReverse(ListNode head,int len){
if (head==null||len<=0){//偶数个节点
return new Result(head,true);
}
else if (len==1){//奇数个节点
return new Result(head.next,true);
}
Result res=isReverse(head.next,len-2);
if (!res.result||res.node==null) return res;//向上传递失败信息
res.result=(head.val==res2021-6-13-剑指笔记01
[Unity学习笔记:FPS游戏制作]角色的移动,旋转与推进上升————(2021.6.13学习笔记)
2021/6/13 刷题笔记括号生成与回溯法(深度优先遍历)