基础知识

记录一下栈实现及操作

  1. public class ArrayDequeStack
  2. {
  3. public void main()
  4. {
  5. ArrayDeque stack = new ArrayDeque();
  6. // 大小
  7. System.out.println(stack.size());
  8. // 依次将三个元素push入"栈"
  9. stack.push("循循渐进Linux");
  10. stack.push("小学语文");
  11. stack.push("时间简史");
  12. // 输出:[时间简史, 小学语文, 循循渐进Linux]
  13. System.out.println(stack);
  14. // 访问第一个元素,但并不将其pop出"栈",输出:时间简史
  15. System.out.println(stack.peek());
  16. // 依然输出:[时间简史, 小学语文, 循循渐进Linux]
  17. System.out.println(stack);
  18. // pop出第一个元素,输出:时间简史
  19. System.out.println(stack.pop());
  20. // 输出:[小学语文, 循循渐进Linux]
  21. System.out.println(stack);
  22. }
  23. }

记录一下Map常用操作

  1. HashMap<String, String > myMap = new HashMap<String, String>(){{
  2. put("a","b");
  3. put("b","b");
  4. }};
  5. {
  6. Object object = new Object();
  7. Object key = new Object();
  8. Object value = new Object();
  9. Map map1 = new HashMap<>();
  10. Map map2 = new TreeMap();
  11. Map map3 = new LinkedHashMap();
  12. map1.get(key);
  13. map1.put("string", object);
  14. map1.putIfAbsent(1, object);
  15. map1.remove(key);
  16. map1.isEmpty();
  17. map1.containsKey(key);
  18. map1.containsValue(value);
  19. map1.getOrDefault(13, 0);
  20. map1.replace(key, value, value);
  21. // 存不存在key 或 value
  22. // 如果指定的键尚未与某个值相关联(或映射到 null )将其与给定值相关联并返回 null ,否则返回当前值。
  23. for (Object key1 : map1.keySet()) {
  24. Object value1 = map1.get(key);
  25. System.out.println(key1 + " = " + value1);
  26. }
  27. // 根据泛型的类型判断该如何进行排序 直接根据key 或者 根据key获取value进行lambda比较器排序
  28. Map<Character, Integer> map = new HashMap<Character, Integer>();
  29. List<Character> list = new ArrayList<Character>(map.keySet());
  30. // 按value 降序排序
  31. Collections.sort(list, (a, b) -> map.get(b) - map.get(a));
  32. // 按key 降序排序
  33. Collections.sort(list, (a, b) -> b.compareTo(a));
  34. }

LeetCode 24

分析1.0

交换相邻的两个节点,需要两个指针 pre p,不修改节点内部的值,意味着只改变原节点next指向,

  1. 空链 或链中只有一个节点 直接返回
  2. ans指向 第一对交换后的相邻节点左侧
  3. 循环终止条件只剩下0或1个元素,可退出终止

失误

  1. 只考虑到了仅有两个元素的交换,如果有3个以上元素的交换,还需要设置last指针指向已交换完成的链表段的最后一个元素
  2. 应将链表分为三部分 ①已操作好链表段 last指向这段尾节点 ②待交换的2个节点③剩余链表段 first指向这段首节点
  3. if(p1.next == null || p1 == null) 就近原则可能报错
  1. class Solution {
  2. public ListNode swapPairs(ListNode head) {
  3. if(head == null || head.next == null){
  4. return head;
  5. }
  6. ListNode ans = new ListNode(-1);
  7. ListNode p1 = head, p2 = head.next, first, last = new ListNode(-2);
  8. // 至少有两个节点
  9. while(true){
  10. first = p2.next;
  11. p2.next = p1;
  12. p1.next = first;
  13. last.next = p2;
  14. last = p1;
  15. if(ans.val == -1){
  16. ans = p2;
  17. }
  18. if(first == null){
  19. break;
  20. }
  21. p1 = first;
  22. p2 = p1.next;
  23. if(p1== null || p2 == null){
  24. break;
  25. }
  26. }
  27. return ans;
  28. }
  29. }

分析2.0

应将链表分为三部分 ①已操作好链表段 last指向这段尾节点 ②待交换的2个节点③剩余链表段 first指向这段首节点

  1. class Solution {
  2. public ListNode swapPairs(ListNode head) {
  3. if(head == null || head.next == null){
  4. return head;
  5. }
  6. ListNode ans = new ListNode(-1);
  7. ListNode p1 = head, p2 = head.next, first = p2.next, last = new ListNode(-1,head);
  8. // 至少有两个节点
  9. while(true){
  10. // last.next 指向p2 p2指向p1 p1指向first
  11. last.next = p2;
  12. p2.next = p1;
  13. p1.next = first;
  14. last = p1;
  15. if(ans.val == -1){
  16. ans = p2;
  17. }
  18. p1 = last.next;
  19. if(p1 == null || p1.next == null){
  20. break;
  21. }
  22. p2 = p1.next;
  23. first = p2.next;
  24. }
  25. return ans;
  26. }
  27. }

LeetCode 19

分析1.0

要求删除链表的倒数第n个节点 思路:设置两个指针,p pre, 间隔n个元素,当p = null 时pre.next = 待删节点

失误 遇到一个奇怪的点 pre.next = head pre.next=pre.next.next head竟然没变

订正 确实是没变

  1. class Solution {
  2. public ListNode removeNthFromEnd(ListNode head, int n) {
  3. if(head == null){
  4. return null;
  5. }
  6. // p最终要指向的是最后一个节点 所以循环终止条件是p.next != null
  7. ListNode pre = new ListNode(101,head), p = head;
  8. int cnt = 1;
  9. while(cnt < n && p != null){
  10. p = p.next;
  11. cnt++;
  12. }// 遍历结束时,p指针指向第n个节点 pre.next = head
  13. System.out.println("p----"+p.val);
  14. System.out.println("pre----"+pre.val);
  15. while(p.next != null){
  16. System.out.println("循环");
  17. p = p.next;
  18. pre = pre.next;
  19. }
  20. // pre指向倒数第n+1个节点
  21. System.out.println(pre.next == head);
  22. pre.next = pre.next.next;
  23. System.out.println(pre.next == head);
  24. System.out.println("head----"+head.val);
  25. System.out.println("pre.next----"+pre.next);
  26. return head;
  27. }
  28. }

修改 返回虚拟头结点的next

  1. class Solution {
  2. public ListNode removeNthFromEnd(ListNode head, int n) {
  3. if(head == null){
  4. return null;
  5. }
  6. // p最终要指向的是最后一个节点 所以循环终止条件是p.next != null
  7. ListNode pre = new ListNode(101,head), p = head, virtualNode = pre;
  8. int cnt = 1;
  9. while(cnt < n && p != null){
  10. p = p.next;
  11. cnt++;
  12. }// 遍历结束时,p指针指向第n个节点 pre.next = head
  13. while(p.next != null){
  14. p = p.next;
  15. pre = pre.next;
  16. }
  17. // pre指向倒数第n+1个节点
  18. pre.next = pre.next.next;
  19. return virtualNode.next;
  20. }
  21. }

分析2.0

p可走n+1步后,pre接着走,这样pre直接就指向了待删除元素的前一个

LeetCode 面试题 02.07. 链表相交

分析1.0

这题一看过去首先想到的就是要逆向遍历,但是又要求不能改变原来链表的结构,便用两个list装下所有数据完成转置,接着开始遍历两个list,找到最后一个相等节点,

  1. public class Solution {
  2. public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
  3. if(headA == null || headB == null){
  4. return null;
  5. }
  6. ListNode p1 = new ListNode(-1,headA), p2 = new ListNode(-2,headB);
  7. List<ListNode> list1 = new LinkedList(), list2 = new LinkedList();
  8. while(p1.next != null){
  9. list1.add(p1.next);
  10. p1 = p1.next;
  11. }
  12. while(p2.next != null){
  13. list2.add(p2.next);
  14. p2 = p2.next;
  15. }
  16. /*if(headA.val != headB.val){
  17. System.out.println("尾节点不同");
  18. return null; // headA headB是始终不变的这么比比的是原链表的首节点
  19. }*/
  20. // 通过日志发现了问题 压根儿就没有转置
  21. for(int i = 0; i < list1.size(); i++){
  22. System.out.println(list1.get(i).val);
  23. }
  24. int cnt = -1;
  25. while(list1.get(cnt+1) == list2.get(cnt+1) && list1.get(cnt+1) != null && list2.get(cnt+1) != null){
  26. System.out.println(list1.get(cnt+1));
  27. cnt++;
  28. }
  29. return list1.get(cnt);
  30. }
  31. }

失误:真是闹了个乌龙

分析2.0

直接插入采用的是尾插法,根本就没有实现元素转置 转置可用栈 可惜超出内存限制了

  1. public class Solution {
  2. public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
  3. if(headA == null || headB == null){
  4. return null;
  5. }
  6. ListNode p1 = new ListNode(-1,headA), p2 = new ListNode(-2,headB);
  7. ArrayDeque<ListNode> stack1 = new ArrayDeque(), stack2 = new ArrayDeque();
  8. while(p1.next != null){
  9. stack1.push(p1.next);
  10. }
  11. while(p2.next != null){
  12. stack2.push(p2.next);
  13. }
  14. // 开始比较选出首个不等节点
  15. ListNode ans = null;
  16. while(true){
  17. p1 = stack1.pop();
  18. p2 = stack2.pop();
  19. if(p1.val != p2.val){
  20. break;
  21. }
  22. ans = p1;
  23. }
  24. return ans;
  25. }
  26. }

分析3.0

看了卡哥的思路,发现自己还是没有准确理解节点相等这个要求

将链表以当前遍历节点为基准分为三段,若A B指向了相同的节点,那之后的那一段一定是相同的 而比较节点是否相同比较的也是ListNode这个引用是否相等(和数组的区别之一)

于是① 获取A B长度,移动长链表头指针headA至以新的headA为头结点的链表长度等于原短链表的长度,开始比较,节点引用相等的点为所求

  1. public class Solution {
  2. public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
  3. ListNode curA = headA;
  4. ListNode curB = headB;
  5. int lenA = 0, lenB = 0;
  6. while (curA != null) { // 求链表A的长度
  7. lenA++;
  8. curA = curA.next;
  9. }
  10. while (curB != null) { // 求链表B的长度
  11. lenB++;
  12. curB = curB.next;
  13. }
  14. curA = headA;
  15. curB = headB;
  16. // 让curA为最长链表的头,lenA为其长度
  17. if (lenB > lenA) {
  18. //1. swap (lenA, lenB);
  19. int tmpLen = lenA;
  20. lenA = lenB;
  21. lenB = tmpLen;
  22. //2. swap (curA, curB);
  23. ListNode tmpNode = curA;
  24. curA = curB;
  25. curB = tmpNode;
  26. }
  27. // 求长度差
  28. int gap = lenA - lenB;
  29. // 让curA和curB在同一起点上(末尾位置对齐)
  30. while (gap-- > 0) {
  31. curA = curA.next;
  32. }
  33. // 遍历curA 和 curB,遇到相同则直接返回
  34. while (curA != null) {
  35. if (curA == curB) {
  36. return curA;
  37. }
  38. curA = curA.next;
  39. curB = curB.next;
  40. }
  41. return null;
  42. }
  43. }

分析4.0

  1. 抽象思维 链表分3段
  2. 明确所求结果落实到链表状态上是个什么情形
  3. 从结果倒推循环起点

LeetCode 142

分析1.0 

从图的出入度考虑,入环节点入度为2,简历<ListNode,<index,int>>哈希表,访问到某一节点时,入度+1,如果当前节点入度为2,返回当前节点index,若节点为null,return -1

但是这样会报错

  1. HashSet<ListNode, <Integer,Integer>> set = new HashSet();

好吧 分析1.0都是错的

订正

要使用的结构为Map 

  1. public class Solution {
  2. public ListNode detectCycle(ListNode head) {
  3. HashMap<ListNode, Integer> map = new HashMap();// 节点,索引
  4. ListNode cur = head;
  5. int index = 0;
  6. while(true){
  7. if(cur == null){
  8. return null;
  9. }
  10. if(map.containsKey(cur)){
  11. return cur;
  12. }else{
  13. map.put(cur,index++);
  14. }
  15. cur = cur.next;
  16. }
  17. }
  18. }

分析2.0

这题其实用不着记录入度,用Set<ListNode> 就行,遍历时查重即可

分析3.0

空间复杂度为O(1) 考虑双指针 滑动窗口这类思想

快慢指针 a指针一次走两步,b指针一次走一步,相当于a指针一次走一步b指针没动 这个思路Mark一下

  1. public class Solution {
  2. public ListNode detectCycle(ListNode head) {
  3. ListNode slow = head;
  4. ListNode fast = head;
  5. while (fast != null && fast.next != null) {
  6. slow = slow.next;
  7. fast = fast.next.next;
  8. if (slow == fast) {// 有环
  9. ListNode index1 = fast;
  10. ListNode index2 = head;
  11. // 两个指针,从头结点和相遇结点,各走一步,直到相遇,相遇点即为环入口
  12. while (index1 != index2) {
  13. index1 = index1.next;
  14. index2 = index2.next;
  15. }
  16. return index1;
  17. }
  18. }
  19. return null;
  20. }
  21. }

参考卡哥 https://programmercarl.com/0142.%E7%8E%AF%E5%BD%A2%E9%93%BE%E8%A1%A8II.html

总结

  1. 总结一个做题抽象思维,把数据看成几个整体,整体之间如何联系、整体之内如何联系
  2. if(p1.next == null || p1 == null) 就近原则可能报错
  3. ListNode pre = new ListNode(5,head) 自定义val值时考虑题目限制 我这里设为负数被系统强制改为绝对值
  4. 链表题考虑虚拟头结点!!!
  5. pre.next = head pre.next=pre.next.next head是不会变的,一直指向那块内存区域 而链表的结构是发生了变化的
  6. 搞清循环终止条件是  p != null 还是 p.next !=null 计数器定位可采取特殊法
  7. 删除节点定位它的前一个节点
  8. 特殊情况一定要优先考虑,有时候不光考虑一个结构有无元素 返回的结果要留意是否为null
  9. 循环是重点 循环的其实条件 终止条件 注意循环前变量值循环后变量值
  10. 快慢指针 a指针一次走两步,b指针一次走一步,相当于a指针一次走一步b指针没动

常用变量名增量更新

size、val、ans、cnt、cur、pre、next、left、right、index、gap

 
 
 

代码随想录算法训练营day04 | leetcode的更多相关文章

  1. 【算法训练营day4】LeetCode24. 两两交换链表中的结点 LeetCode19. 删除链表的倒数第N个结点 LeetCode面试题 02.07. 链表相交 LeetCode142. 环形链表II

    [算法训练营day4]LeetCode24. 两两交换链表中的结点 LeetCode19. 删除链表的倒数第N个结点 LeetCode面试题 02.07. 链表相交 LeetCode142. 环形链表 ...

  2. 【算法训练营day7】LeetCode454. 四数相加II LeetCode383. 赎金信 LeetCode15. 三数之和 LeetCode18. 四数之和

    [算法训练营day7]LeetCode454. 四数相加II LeetCode383. 赎金信 LeetCode15. 三数之和 LeetCode18. 四数之和 LeetCode454. 四数相加I ...

  3. 【算法训练营day1】LeetCode704. 二分查找 LeetCode27. 移除元素

    [算法训练营day1]LeetCode704. 二分查找 LeetCode27. 移除元素 LeetCode704. 二分查找 题目链接:704. 二分查找 初次尝试 看到题目标题是二分查找,所以尝试 ...

  4. 【算法训练营day8】LeetCode344. 反转字符串 LeetCode541. 反转字符串II 剑指Offer05. 替换空格 LeetCode151. 翻转字符串里的单词 剑指Offer58-II. 左旋转字符串

    [算法训练营day8]LeetCode344. 反转字符串 LeetCode541. 反转字符串II 剑指Offer05. 替换空格 LeetCode151. 翻转字符串里的单词 剑指Offer58- ...

  5. 【算法题 14 LeetCode 147 链表的插入排序】

    算法题 14 LeetCode 147 链表的插入排序: 解题代码: # Definition for singly-linked list. # class ListNode(object): # ...

  6. 代码随想录第十三天 | 150. 逆波兰表达式求值、239. 滑动窗口最大值、347.前 K 个高频元素

    第一题150. 逆波兰表达式求值 根据 逆波兰表示法,求表达式的值. 有效的算符包括 +.-.*./ .每个运算对象可以是整数,也可以是另一个逆波兰表达式. 注意 两个整数之间的除法只保留整数部分. ...

  7. 代码随想录第八天 |344.反转字符串 、541. 反转字符串II、剑指Offer 05.替换空格 、151.翻转字符串里的单词 、剑指Offer58-II.左旋转字符串

    第一题344.反转字符串 编写一个函数,其作用是将输入的字符串反转过来.输入字符串以字符数组 s 的形式给出. 不要给另外的数组分配额外的空间,你必须原地修改输入数组.使用 O(1) 的额外空间解决这 ...

  8. Manacher算法学习笔记 | LeetCode#5

    Manacher算法学习笔记 DECLARATION 引用来源:https://www.cnblogs.com/grandyang/p/4475985.html CONTENT 用途:寻找一个字符串的 ...

  9. 程序员进阶之算法练习:LeetCode专场

    欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~ 本文由落影发表 前言 LeetCode上的题目是大公司面试常见的算法题,今天的目标是拿下5道算法题: 题目1是基于链表的大数加法,既考察基本 ...

  10. 【算法题目】Leetcode算法题思路:两数相加

    在LeetCode上刷了一题比较基础的算法题,一开始也能解出来,不过在解题过程中用了比较多的if判断,看起来代码比较差,经过思考和改进把原来的算法优化了. 题目: 给出两个 非空 的链表用来表示两个非 ...

随机推荐

  1. 第二十五节:scrapy爬虫识别验证码(四)手绘验证码识别

    一.介绍 今天主要介绍的是微博客户端在登录时出现的四宫格手绘验证码,不多说直接看看验证码长成什么样.        二.思路 1.由于微博上的手绘验证码只有四个宫格,且每个宫格之间都有有向线段连接,所 ...

  2. pandas中groupby的使用

    一.缘由 在爬取大量的数据之后,需要对数据进行分组的处理,于是就使用了groupby,但是我需要的并不是分组之后数据的聚合分析,我需要的是原生的某些数据.但是却找不到网上的相关案例.于是,我就自己尝试 ...

  3. Spring IOC源码(一):IOC容器启动流程核心方法概览

    Spring有两种方式加载配置,分别为xml文件.注解的方式,对于xml配置的方式相信大家都不陌生,往往通过new ClassPathXmlApplicationContext("*.xml ...

  4. Jenkins服务器上创建项目和配置

    大体步骤:General(基础配置)-->源码管理-->构建触发器-->构建环境-->构建-->构建后操作 1.创建一个工程 2.General(基础配置) 仅需填写标准 ...

  5. 三个小任务掌握List、Set、Map

    任务一: ArrayList.Vector 和 LinkedList 都实现了 List 接口,对它们分别进行如下操作后比 较它们的不同,然后形成初步耗时报告(三种不同 List 的耗时): 追加元素 ...

  6. SQL审核平台Yearning

    1.关于Yearming Yearming是一个Sql审核平台,底层使用Go语言,安装和部署方式也很便捷 项目地址 https://guide.yearning.io/install.html git ...

  7. SQLMap入门——获取数据库用户的密码

    列出数据库用户的密码 如果当前用户有读取包含用户密码的权限,SQLMap会先列举出用户,然后列出Hash,并尝试破解 python sqlmap.py -u http://localhost/sqli ...

  8. Less-1(GET字符型)

    union联合注入(方法一) 进入靶场 按照要求提交一个id:http://192.168.121.131/sqli/Less-1/?id=1 数据库执行语句:select * from news w ...

  9. tempdb大量闩锁等待问题分析

    背景 客户业务系统升级后,高峰期运行缓慢,在SQL专家云上看到数据库出现严重等待,需要分析原因并紧急处理. 现象 登录到SQL专家云中,进入实时可视化页面,在活动会话里面看到有大量资源等待的会话.   ...

  10. Springboot启动时加载

    @Component public class SpringBootInitialization1 implements ServletContextListener { @Override publ ...