LeetCode剑指Offer刷题总结(一)
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刷题总结(一)的更多相关文章
- 牛客网剑指offer刷题总结
二维数组中的查找: 题目描述:在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序.请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数. 两 ...
- 剑指offer刷题(Tree)
开篇 二刷剑指offer了,本来用Tyora记的笔记,发现字数到四万了就变得好卡o(╥﹏╥)o,刚好开始写博客,就转过来吧,记下来子自己看.不废话,开刷... JZ26. 树的子结构 输入两棵二叉树A ...
- 剑指offer刷题
1.面试题43. 1-n整数中1出现的次数 输入一个整数 n ,求1-n这n个整数的十进制表示中1出现的次数. 例如,输入12,1-12这些整数中包含1 的数字有1.10.11和12,1一共出现了5次 ...
- 剑指offer ------ 刷题总结
面试题3 -- 搜索二维矩阵 写出一个高效的算法来搜索 m × n矩阵中的值. 这个矩阵具有以下特性: 1. 每行中的整数从左到右是排序的. 2. 每行的第一个数大于上一行的最后一个整数. publi ...
- 剑指offer刷题记录
目录 二维数组中的查找 替换空格 从尾到头打印链表 反转链表 重建二叉树 用两个栈实现队列 旋转数组的最小数字 斐波拉切数列 跳台阶 变态跳台阶 矩形覆盖 二进制中1的个数 数值的整次方 链表中倒数第 ...
- 剑指offer刷题总结
★ 二维数组的查找 在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序.请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否 ...
- 剑指offer刷题笔记
删除链表中重复的结点:较难 在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针. 例如,链表1->2->3->3->4->4- ...
- 剑指offer刷题(算法类_2)
排序 035-数组中的逆序对(归并排序) 题目描述 题解 代码 复杂度 029-最小的K个数(堆排序) 题目描述 题解 代码 复杂度 029-最小的K个数(快速排序) 题目描述 题解 代码 复杂度 位 ...
- 剑指offer刷题(算法类_1)
斐波那契数列 007-斐波拉契数列 题目描述 题解 代码 复杂度 008-跳台阶 题目描述 题解 代码 复杂度 009-变态跳台阶 题目描述 题解 代码 复杂度 010-矩形覆盖 题目描述 题解 代码 ...
随机推荐
- NGK:价值对标比特币,上线暴涨4558%,下一个财富暴增风口
近期,美股行情多变,一直饱受争议的比特币也成了其中的"弄潮儿".看多者认为,机构的兴趣有助于支撑比特币作为对冲美元疲软和通胀的工具. 特别是今年1月底的时候,马斯克将推特简介更改为 ...
- 「NGK每日快讯」2021.1.7日NGK第65期官方快讯!
- Baccarat流动性挖矿的收益能否持续?该如何参与Baccarat流动性挖矿?
2020年DeFi市场火热,众多投资机构纷纷入场,分享这场资本盛宴.然而,目前市面上大多数DeFi项目手续费高昂,小资金的投资者无法入市.为了让更多的用户参与其中,NGK推出了Baccarat流动性挖 ...
- NGK全球启动大会正式启动,资产上链的前景与机会在哪?
据彭博社报道,加州时间11月25日,NGK全球启动大会在美国硅谷圆满落幕,本次NGK全球启动大会为NGK全球化进程正式拉开了帷幕. 众多业界人士共襄盛举,共同进行探讨未来公链发展的去向和契机. 当前, ...
- WPF权限控制——【3】数据库、自定义弹窗、表单验证
你相信"物竞天择,适者生存"这样的学说吗?但是我们今天却在提倡"尊老爱幼,救死扶伤",帮助并救护弱势群体:第二次世界大战期间,希特勒认为自己是优等民族,劣势民族 ...
- linux下安装mysql8.0.x步骤
1.下载mysql mysql官网:https://dev.mysql.com/downloads/mysql/ 将下载的mysql上传打linux 2.解压并重命名 [root@rsyncClien ...
- 源码分析:Phaser 之更灵活的同步屏障
简介 Phaser 是 JDK 1.7 开始提供的一个可重复使用的同步屏障,功能类似于CyclicBarrier和CountDownLatch,但使用更灵活,支持对任务的动态调整,并支持分层结构来达到 ...
- TERSUS无代码开发(笔记02)-简单实例加法
简单实例加法 1.用户端元件(显示元件)(40个) 图标 英文名称 元件名称 使用说明 服务器端 客户端 Pane 显示块 是一个显示块,是HTML的div标签 √ Row 行 行元件中的显示元件 ...
- Linux的启动过程及init进程
Linux下有三个特殊进程: idle进程(pid=0)idle进程其前身是系统创建的第一个进程,0号进程,也唯一一个没有通过fork()或者kernel_thread产生的进程,由系统自动创建,运行 ...
- 学习java之基础语法(一)
学习java之基础语法(一) 基本语法 编写 Java 程序时,应注意以下几点: 大小写敏感:Java 是大小写敏感的,这就意味着标识符 Hello 与 hello 是不同的. 类名:对于所有的类来说 ...