LeetCode过程中值得反思的细节

以下题号均指LeetCode剑指offer题库中的题号

本文章将每周定期更新,当内容达到10题左右时将会开下一节。

二维数组越界问题04

public static void main(String[] args) {
int[][]x = {{}};
System.out.println(x.length+" "+x[0].length);
int[][]y = {{1}};
System.out.println(y.length+" "+y[0].length);
int[][]z = {};
System.out.println(z.length);
}

在遇到二维数组时,要注意为空的不同情况

String和char[]的相互转换05

char[] s = {'a','b','c'};
String s1 = new String(s); //这里为String的构造函数
String s2 = "abc";
System.out.println(s1.equals(s2));
System.out.println(s1.equals(s));
System.out.println(s2.equals(s)); char[] s3 = new char[8];
s3[0]='a';s3[1]='b';s3[2]='c';
String s4 = new String(s3);
System.out.println(s4.equals(s2));
System.out.println(s2.equals(s4.trim()));//或者括号内为new String(s3,0,3) String(char[],off,length)

注意,char[]强制转换为String,相互比较结果不经处理恒为false。

原因:由equals源码决定

public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String aString = (String)anObject;
if (!COMPACT_STRINGS || this.coder == aString.coder) {
return StringLatin1.equals(value, aString.value);
}
}
return false;
}

String对象的内部也是一个char数组,通过char数组创建String时,如果不指定start和count,会将使用整个数组,即连同后面的空字符,输出结果不会受到影响。另外,String.trim()就是删除String 的char数组 前后的空白字符和空字符,使用trim()后再比较就得到值完全一样的String了。

集合数组互转06

    // int[] 转 List<Integer>
List<Integer> list1 = Arrays.stream(data).boxed().collect(Collectors.toList());
// Arrays.stream(arr) 可以替换成IntStream.of(arr)。
// 1.使用Arrays.stream将int[]转换成IntStream。
// 2.使用IntStream中的boxed()装箱。将IntStream转换成Stream<Integer>。
// 3.使用Stream的collect(),将Stream<T>转换成List<T>,因此正是List<Integer>。 // int[] 转 Integer[]
Integer[] integers1 = Arrays.stream(data).boxed().toArray(Integer[]::new);
// 前两步同上,此时是Stream<Integer>。
// 然后使用Stream的toArray,传入IntFunction<A[]> generator。
// 这样就可以返回Integer数组。
// 不然默认是Object[]。 // List<Integer> 转 Integer[]
Integer[] integers2 = list1.toArray(new Integer[0]);
// 调用toArray。传入参数T[] a。这种用法是目前推荐的。
// List<String>转String[]也同理。 // List<Integer> 转 int[]
int[] arr1 = list1.stream().mapToInt(Integer::valueOf).toArray();
// 想要转换成int[]类型,就得先转成IntStream。
// 这里就通过mapToInt()把Stream<Integer>调用Integer::valueOf来转成IntStream
// 而IntStream中默认toArray()转成int[]。 // Integer[] 转 int[]
int[] arr2 = Arrays.stream(integers1).mapToInt(Integer::valueOf).toArray();
// 思路同上。先将Integer[]转成Stream<Integer>,再转成IntStream。 // Integer[] 转 List<Integer>
List<Integer> list2 = Arrays.asList(integers1);
// 最简单的方式。String[]转List<String>也同理。 // 同理
String[] strings1 = {"a", "b", "c"};
// String[] 转 List<String>
List<String> list3 = Arrays.asList(strings1);
// List<String> 转 String[]
String[] strings2 = list3.toArray(new String[0]);

ArrayList.get(); ArrayList.set(index,value);

重建二叉树的两种方法07

根据先序和中序递归还原二叉树

先序:根节点,{左子树},{右子树}

中序:{左子树},根节点,{右子树}

两种思路:递归和迭代

递归:

class Solution {
private HashMap<Integer,Integer> indexmap = new HashMap<>(); public TreeNode myBuildTree(int[] preorder, int[] inorder, int preorderleft,int preorderright,int inorderleft,int inorderright){
if(preorderleft>preorderright)
return null;
TreeNode root = new TreeNode(preorder[preorderleft]);
int inorderroot = indexmap.get(preorder[preorderleft]);
int prelen = inorderroot - inorderleft;
root.left = myBuildTree(preorder,inorder,preorderleft+1,preorderleft+prelen,inorderleft,inorderroot-1);
root.right = myBuildTree(preorder,inorder,preorderleft+prelen+1,preorderright,inorderroot+1,inorderright);
return root;
} public TreeNode buildTree(int[] preorder, int[] inorder) {
int len = preorder.length;
for(int i = 0 ; i < len ; i++){
indexmap.put(inorder[i],i);
}
return myBuildTree(preorder,inorder,0,len-1,0,len-1);
}
}

将以上算法后四个参数 (int preorderleft,int preorderright,int inorderleft,int inorderright) 分别称为A,B,C,D,则A和B相当于建立的树的先序遍历的左边指针和右边指针,C和D相当于中序遍历的左指针和右指针,用来标记多次遍历过程的左子树边界和右子树边界。

迭代思路中,则需要用到栈stack

可利用deque接口实现stack

  • deque支持两端元素插入和移除的线性集合。 名称deque是“双端队列”的缩写,通常发音为“deck”。 大多数Deque实现对它们可能包含的元素的数量没有固定的限制,但是该接口支持容量限制的deques以及没有固定大小限制的deques。
Deque<TreeNode> stack = new LinkedList<TreeNode>();

stack.peek()取栈顶元素,不弹出

stack.push()压入元素

stack.pop()取栈顶元素,并弹出

class Solution {
public TreeNode buildTree(int[] preorder, int[] inorder) {
if(preorder == null || preorder.length == 0)
return null;
int len = preorder.length;
int index = 0; //中序遍历的指针
Deque<TreeNode> stack = new LinkedList<>();
TreeNode root = new TreeNode(preorder[0]);
stack.push(root);
TreeNode node;
for(int i = 1 ; i < len ; i++){
if((node = stack.peek()).val != inorder[index]){
node.left = new TreeNode(preorder[i]);
stack.push(node.left);
}
else{
while(!stack.isEmpty() && stack.peek().val==inorder[index]){ //stack存当前构造树的左节点,可能会有多个构造的树
node = stack.pop();
index++;
}
node.right = new TreeNode(preorder[i]);
stack.push(node.right);
}
}
return root;
}
}

在这个思路中,主要应用中序遍历的第一个元素将是树的左边界,以先序遍历的顺序与该元素进行比较,若根节点与其相同,则无左子树;不同的话即为压入栈的栈顶元素的左节点。这个思路主要在于先序遍历和中序遍历的过程特点,递归主要利用的是先序和中序的结构特点。

重要在于理解:每次遍历过程中,操作的是栈顶元素,而遍历的当前i在栈顶元素的后面。

利用两个栈实现队列 09

队列要实现的是先进先出,而栈实现的是先进后出,所以可以建立两个stack

栈1负责压入元素,而当需要删除的时候,只需将栈1中的元素转入栈2

stack2.push(stack1.pop());

这样的话,栈2中,栈顶元素为最开始添加进去的元素,为队列头,直至栈2删除完后,若栈1还有元素,继续转移,若没有,则返回0。


斐波那契数列 10

此题非常简单,但是实现过程需要注意,利用递归会造成大量的重复计算

建议使用动态规划,开辟两个Int空间记录状态

根据状态转移方程进行计算

Java中int的取值范围为-2147483648到+2147483647,4个字节32位,可思考补码和原码的相关知识

旋转数组的最小数组11(二分查找)

本题乍一看就会考虑到遍历,但是时间复杂度有些高O(n),思考一下有没有更加快的方法

public static int minArray(int[] numbers) {
int len = numbers.length;
int low = 0,high = len-1;
int mid ;
while(low != high){
mid = low + (high - low)/2;
System.out.println(mid);
if(numbers[mid]>numbers[high])
low = mid+1;
if(numbers[mid]<numbers[high]) //正确答案为前加else
high = mid;
else
high--;
}
System.out.println(low+" "+high+" "+len);
return numbers[low];
}

注意,这个例子容易犯错,在实现if的时候,第一个if判断之后,进行第二个判断,low改变mid却没有改变,注意else

本题的二分查找应用于,numbers[high]这个元素,大于它的一定是ans左边的,小于它的一定是ans右边的,而等于它时,说明numbers[high]不是最小值,将high向左调一位。

矩阵中的路径12(DFS)

这个例子是典型的深度搜索,思路比较容易想到

但是需要注意的点为:

每次深搜结束后,需要还原矩阵,不然的话假如本次搜索返回false,下次搜索的时候矩阵已经改变,结果不正确。

机器人运动范围13(BFS)

首先涉及到一个知识点,Java中的break在多重循环中只能跳出所在循环

public static void main(String[] args) {
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
if(j<2)
System.out.println(i+" "+j);
else
break;
}
}
}

输出结果为:

此题需要注意的是,范围必须是从[0, 0]出发可达的。本题还是利用一个栈或队列,将新搜索的点添加进去,再出元素,重新搜索。同时需要建立标志位,搜索过的位置就不需要再次搜索。

LeetCode剑指Offer刷题总结(一)的更多相关文章

  1. 牛客网剑指offer刷题总结

    二维数组中的查找: 题目描述:在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序.请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数. 两 ...

  2. 剑指offer刷题(Tree)

    开篇 二刷剑指offer了,本来用Tyora记的笔记,发现字数到四万了就变得好卡o(╥﹏╥)o,刚好开始写博客,就转过来吧,记下来子自己看.不废话,开刷... JZ26. 树的子结构 输入两棵二叉树A ...

  3. 剑指offer刷题

    1.面试题43. 1-n整数中1出现的次数 输入一个整数 n ,求1-n这n个整数的十进制表示中1出现的次数. 例如,输入12,1-12这些整数中包含1 的数字有1.10.11和12,1一共出现了5次 ...

  4. 剑指offer ------ 刷题总结

    面试题3 -- 搜索二维矩阵 写出一个高效的算法来搜索 m × n矩阵中的值. 这个矩阵具有以下特性: 1. 每行中的整数从左到右是排序的. 2. 每行的第一个数大于上一行的最后一个整数. publi ...

  5. 剑指offer刷题记录

    目录 二维数组中的查找 替换空格 从尾到头打印链表 反转链表 重建二叉树 用两个栈实现队列 旋转数组的最小数字 斐波拉切数列 跳台阶 变态跳台阶 矩形覆盖 二进制中1的个数 数值的整次方 链表中倒数第 ...

  6. 剑指offer刷题总结

    ★ 二维数组的查找 在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序.请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否 ...

  7. 剑指offer刷题笔记

    删除链表中重复的结点:较难 在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针. 例如,链表1->2->3->3->4->4- ...

  8. 剑指offer刷题(算法类_2)

    排序 035-数组中的逆序对(归并排序) 题目描述 题解 代码 复杂度 029-最小的K个数(堆排序) 题目描述 题解 代码 复杂度 029-最小的K个数(快速排序) 题目描述 题解 代码 复杂度 位 ...

  9. 剑指offer刷题(算法类_1)

    斐波那契数列 007-斐波拉契数列 题目描述 题解 代码 复杂度 008-跳台阶 题目描述 题解 代码 复杂度 009-变态跳台阶 题目描述 题解 代码 复杂度 010-矩形覆盖 题目描述 题解 代码 ...

随机推荐

  1. NGK全网算力总量增加,SPC前景广阔

    日前,根据NGK官方公布的数据显示,NGK全网算力总量达到550.96万,比早前预估的500万算力增加了50.96万,并且随着SPC空投的持续,还有不少生态建设者在持续涌入NGK算力市场.那么,是什么 ...

  2. CloudQuery v1.2.1 版本发布

    欢迎来到 CloudQuery v1.2.1 版本发布会. 上次 v1.2.0 版本发布收到广大朋友们的热烈反响,大家提出了很多宝贵建议,揪出了不少 Bug.在此,我们表示由衷感谢.问题和建议我们都会 ...

  3. NDK android Error:Expected caller to ensure valid ABI: MIPS

    android studio 安装NDK之后,报错 Error:Expected caller to ensure valid ABI: MIPS 环境: android studio 2.3 gra ...

  4. Redis-第九章节-动态字符串

    目录 概述 SDS(动态字符串) SDS(动态字符串)与c语言字符串的区别 1.概述 String类型底层实现的简单动态字符串sds,是可以修改的字符串.它采用预分配冗余空间的方式来减少内存的频繁分配 ...

  5. JVM必不可少的知识

    1.Java垃圾回收机制 对象被判断为垃圾的标准:没有被其他对象引用 2.判断对象是否可被回收 (1)引用计数算法 判断对象的引用数量 通过判断对象的引用数量来决定对象是否可以被回收 每个对象实例都有 ...

  6. Elasticsearch 及其套件的安装上手

    前言 本文主要讲解Elasticsearch及其套件Kibana.Logstash的安装及启动,还讲解如何导入数据用于后续的实验. 说明:Elasticsearch是基于Java开发的,所以如果是下载 ...

  7. 010_HTML5

    目录 初识HTML 什么是HTML HTML发展史 HTML5的优势 W3C标准 常见IDE IDEA开发HTML IDEA创建HTML文件,并用浏览器打开 配置浏览器 HTML基础 HTML基本结构 ...

  8. 1063 Set Similarity——PAT甲级

    1063 Set Similarity Given two sets of integers, the similarity of the sets is defined to be Nc/Nt*10 ...

  9. 你真的搞懂了Java中的<<、>>、>>>运算符嘛?

    在搞懂<<.>>.>>>之前,我们需要先了解二进制中的源码.反码.补码... 二进制中的原码.反码.补码 有符号数: 对于有符号数而言,符号的正.负机器是无法 ...

  10. Linux速通05 文件处理与编辑

    使用 cat 命令进行文件的纵向合并 # 例:使用 cat 命令将 baby.age.baby.weight.baby.sex 这三个文件纵向合并为 baby文件 * cat baby.age bab ...