删除链表中的节点
要点:node.val = node.next.val
/** * Definition for singly-linked list. * public class ListNode { * int val; * ListNode next; * ListNode(int x) { val = x; } * } */ class Solution { public void deleteNode(ListNode node) { node.val = node.next.val; node.next = node.next.next; } }删除链表的倒数第 N 个结点
要点:
方法1:记录length,然后减掉n,找到n的前一个节点,不用dummy的话,就特判一下头节点
/** * Definition for singly-linked list. * 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 Solution { public ListNode removeNthFromEnd(ListNode head, int n) { //记录长度 ListNode temp1 = head; int length = 0; while(temp1 != null){ length++; temp1 = temp1.next; } int target = length - n; if(target == 0){ return head.next; } ListNode dummy = new ListNode(-1, head); ListNode temp2 = dummy.next; for(int i = 1; i < target; i++){ temp2 = temp2.next; } temp2.next = temp2.next.next; return dummy.next; } }方法2:dummy。left。right,right先走n,然后right到last的时候,left在倒数n+1节点上
/** * Definition for singly-linked list. * 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 Solution { public ListNode removeNthFromEnd(ListNode head, int n) { ListNode dummy = new ListNode(0,head); ListNode left = dummy; ListNode right = dummy; while(n-- > 0){ right = right .next; } while(right.next != null){ right = right.next; left = left.next; } left.next = left.next.next; return dummy.next; } }删除排序链表中的重复元素
要点:cur,然后对比cur.next
/** * Definition for singly-linked list. * 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 Solution { public ListNode deleteDuplicates(ListNode head) { if(head == null){ return head; } ListNode cur = head; while(cur.next != null){ if(cur.next.val == cur.val){ cur.next = cur.next.next; }else{ cur = cur.next; } } return head; } }删除排序链表中的重复元素 II
要点:需要dummy,cur.next 和cur.next,next
/** * Definition for singly-linked list. * 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 Solution { public ListNode deleteDuplicates(ListNode head) { //需要哨兵节点,因可能删除头节点 ListNode dummy = new ListNode(-1, head); ListNode cur = dummy; while(cur.next != null && cur.next.next != null){ int val = cur.next.val; if(cur.next.next != null && cur.next.next.val == val){ while(cur.next != null && cur.next.val == val){ cur.next = cur.next.next; } }else{ cur = cur.next; } } return dummy.next; } }随机知识
JVM内存模型-JVM 运行时数据区有哪些?各自放什么?
候选人:
好的,JVM 运行时数据区是 Java 程序运行的内存基础,一共分为五个核心区域。我按线程共享和线程私有分成两类来说。
先总览整体架构
线程共享的有两块:堆和方法区。线程私有的有三块:虚拟机栈、本地方法栈、程序计数器。
线程私有的意思是每个线程都有一份独立的内存空间,线程结束自动释放,互不干扰。线程共享的意思是所有线程都能访问同一块内存,这也是多线程并发问题产生的根源。
逐一详解五个区域
第一,堆。堆是 JVM 内存中最大的一块,所有通过new创建出来的对象和数组都分配在堆上。它是垃圾回收器重点管理的区域,所以也叫做“GC 堆”。堆里保存的是每个对象的实例数据,比如一个 Person 对象里 name 和 age 的具体值。堆是线程共享的,所有线程都可以访问堆里的对象。因为堆里对象生命周期复杂,有朝生夕死的,也有长期存活的,所以现在 JVM 把堆逻辑上分成年轻代和老年代,分别用不同的垃圾回收策略处理。
第二,方法区。方法区存放的是类的元信息,也就是类被加载后 JVM 需要记录的结构性数据,包括类的版本、字段、方法、接口、静态变量、常量池,还有即时编译器编译后的代码缓存。它也是线程共享的。JDK7 及之前,方法区的实现在堆里,叫永久代,大小固定,容易 OOM。JDK8 开始,方法区的实现移到了本地内存里,改叫元空间,大小默认不限制,只受物理内存限制,更灵活,也减少了堆的 GC 压力。经常聊的“运行时常量池”也在方法区里,字符串常量池在 JDK7 时被移到了堆里,因为堆比永久代空间大,GC 更积极,可以减少 OOM。
第三,虚拟机栈。每个线程启动时,JVM 会给它分配一个独立的虚拟机栈。栈里存的不是对象,而是一个一个的栈帧。每调用一个方法,就创建一个栈帧压入栈顶,方法执行完,栈帧弹出。栈帧里主要存三类数据:一是局部变量表,存放方法内部定义的局部变量,包括基本类型的值和对象的引用(对象本身在堆里,栈里只存指向堆的指针);二是操作数栈,JVM 执行字节码指令时用于计算的中间数据暂存区域;三是返回值等信息。栈内存由 JVM 自动管理,方法结束栈帧弹出,内存就释放了。如果方法递归调用次数过多,栈帧撑满整个栈,就会抛出 StackOverflowError。
第四,本地方法栈。它和虚拟机栈结构类似,但服务对象不同。虚拟机栈为 Java 方法服务,本地方法栈为 Native 方法服务,也就是 Java 调用底层 C/C++ 写的操作系统接口时使用。比如Thread.start()底层创建操作系统线程,就会用到本地方法栈。
第五,程序计数器。它是五块内存中最小的,每个线程都有一个独立的程序计数器。它只记录一个信息:当前线程正在执行的字节码指令的行号。CPU 在多线程间来回切换执行,每次切回来的时候,线程必须知道“上一轮我执行到哪一行了”,这就是程序计数器的意义。这个区域是 JVM 规范中唯一没有规定任何 OutOfMemoryError 的区域。
用一句代码把五个区域串起来
拿String s = new String("hello")这句代码来说:
s这个引用变量在虚拟机栈的局部变量表里。new String("hello")这个对象实例分配在堆里。String这个类的元信息(类名、有哪些方法、字段)存放在方法区里。- 执行这行代码时,当前线程执行到第几行由程序计数器记录。
- 如果在 Native 方法中创建对象,本地方法栈会参与进来。
这样就能把五个区域和日常写代码的变量、对象、类信息一一对上。
碎碎念:后续会更新每天学习的八股和算法 题,开始准备秋招的第21天。努力连续更新100天!以后每天就按,秋招项目【java+agent】,科研,必做项目,算法,八股,锻炼身体来总结。
总结:今天效率巨低,还是算法题及时反馈感强,不想学其他的,不行!以后要以程序员为职业,首先就是要热爱代码呀!!!!!加油加油加油
1.算法要系统过一遍【灵神】8/27【晚上】2h
2.秋招项目,【java】开始实际看业务,2.9/10;无
【agent】还在学,决定把helloagent看一遍,5/16;无
3.科研要跑一下,无
4.检测项目也得总结文档,无,
5.训练项目看看先选择好,无,
6.背八股,无
7.锻炼身体,无
反思:昨天玩手机起得太晚,周末一点不想学习,自己规划的太不合理,当你熬夜的时候就应该知道今天完不成任务,安排事情应该要往前看两步,一天真正清醒的时间很少的呀。
这周相当于啥也没干。
第三周总结改进
1:不要熬夜,不要向明天借时间,今天的事情今天就要干完。
2.运动不能停止
3.相信自己,增强对时间的把控力,
4.得每天看点面经还是,保持状态
5.脑子动起来,感觉现在脑子特别笨,看点脑筋急转弯
————————————————