目录
1 左神部分集锦
2 Leetcode前150题
3 牛客网剑指offer
4 JavaG
5 题目中的细节处理
3 牛客网剑指offer
3.1 纯思路
3.1.1 JZ01 二维数组中的查找
(1)定义两个变量,行变量row和列变量col
(2)利用while和if条件判。若是当前数小于target,row++;若是当前数大于target,col--。
(3)若搜索到相等,直接返回true
(4)若退出while后仍然没有返回,则返回false
注意:利用while,不用两层for,可以避免了整个二维数组的遍历
3.1.2 JZ02 替换空格
思路:利用一个新的StringBuffer。遍历原StringBuffer,若不为空格,直接加入新buffer尾部,否则append("%20")
3.1.3 JZ05 用两个栈实现队列
思路:一个栈用来添加元素,一个栈用来弹出元素。重点是:在添加或弹出元素前,必须先弹出另一个栈的所有元素到当前栈。
public class Solution {
Stack<Integer> stack1 = new Stack<Integer>();
Stack<Integer> stack2 = new Stack<Integer>();
public void push(int node) {
while(!stack2.isEmpty()){
stack1.push(stack2.pop());
}
stack1.push(node);
}
public int pop() {
while(!stack1.isEmpty()){
stack2.push(stack1.pop());
}
return stack2.pop();
}
}
3.1.4 JZ06 旋转数组的最小数字
思路:二分法。
我们的目的是:当进行一次比较时,一定能够确定答案在mid的某一侧。一次比较为 arr[mid]跟谁比的问题。
一般的比较原则有:
· 如果有目标值target,那么直接让arr[mid] 和 target 比较即可。
· 如果没有目标值,一般可以考虑 端点
这里我们把target 看作是右端点,来进行分析,那就要分析以下三种情况,看是否可以达到上述的目标。
· 情况1,arr[mid] > target:4 5 6 1 2 3
arr[mid] 为 6, target为右端点 3, arr[mid] > target, 说明[first ... mid] 都是 >= target 的,因为原始数组是非递减,所以可以确定答案为 [mid+1...last]区间,所以 first = mid + 1
· 情况2,arr[mid] < target:5 6 1 2 3 4
arr[mid] 为 1, target为右端点 4, arr[mid] < target, 说明答案肯定不在[mid+1...last],但是arr[mid] 有可能是答案,所以答案在[first, mid]区间,所以last = mid;
· 情况3,arr[mid] == target:
如果是 1 0 1 1 1, arr[mid] = target = 1, 显然答案在左边
如果是 1 1 1 0 1, arr[mid] = target = 1, 显然答案在右边
所以这种情况,不能确定答案在左边还是右边,那么就让last = last - 1;慢慢缩少区间,同时也不会错过答案。
public class Solution {
public int minNumberInRotateArray(int [] array) {
if (array.length == 0) return 0;
int first = 0, last = array.length - 1;
while (first < last) { // 最后剩下一个元素,即为答案
if (array[first] < array[last]) { // 提前退出
return array[first];
}
int mid = first + ((last - first) >> 1);
if (array[mid] > array[last]) { // 情况1
first = mid + 1;
}
else if (array[mid] < array[last]) { //情况2
last = mid;
}
else { // 情况3
--last;
}
}
return array[first];
}
}
3.1.5 JZ07 斐波那契数列
思路:典型的递归。此外还可以用动态规划等。
3.1.6 JZ08 跳台阶
思路:递归。
3.1.7 JZ09 变态跳台阶
思路:从数学公式中看出的递归方法。
易知 f(n)=f(n-1)+f(n-2)+……f(1)
f(n-1)=f(n-2)+……f(1)
两式相减得f(n)=2f(n-1)
3.1.8 JZ10 矩形覆盖
思路:递归,或记忆性递归。
可以得出:f[n] = f[n-1] + f[n-2],初始条件f[1] = 1, f[2] =2
3.1.9 JZ11 二进制中1的个数
思路:利用位运算,直接找到从右向左第一个1的位置
public int NumberOf1(int n) {
int count = 0;
while(n != 0){
count++;
n = n & (n - 1);
}
return count;
}
3.1.10 JZ12 数值的整数次方
3.1.11 JZ13 调整数组顺序使奇数位于偶数前面
思路:利用两个队列,第一次遍历数组时,将奇数和偶数分别放入对应队列;第二次遍历两个队列,将元素放回数组
3.1.12 JZ19 顺时针打印矩阵
思路:按层打印,每个层用左上角和右下角两个点选中。
3.1.13 JZ20 包含min函数的栈
思路:两个栈,min栈每次保存当前栈元素的最小值
3.1.14 JZ21 栈的压入、弹出序列
思路:定义一个栈,遍历数组A,对于每个元素,先压入栈,再循环弹出当前栈顶与数组B当前下标相同的元素。算法结束,若栈为空,则返回true。
3.1.15 JZ27 字符串的排列
思路:回溯
3.1.16 JZ28 数组中出现次数超过一半的数字
思路一:遍历数组,利用哈希表记录元素个数;再遍历哈希表,判断哪个元素个数超过一半
思路二:利用题目信息,直接排序数组,返回最中间元素即可。
3.1.17 JZ29 最小的K个数
思路:先排序,再取前k个数
3.1.18 JZ30 连续子数组的最大和
思路一:动态规划
思路二:利用全局变量保存最大值,最大值为负数,直接置0,遍历数组往后加
3.1.19 JZ31 整数中1出现的次数
3.1.20 JZ32 把数组排成最小的数
思路:贪心算法。
(1)将原数组转为字符串存在list中
(2)自定义Comparator对List进行排序
(3)逐位比较两个字符串,若到达字符串尾部,返回首部继续比较。
(4)利用StringBuffer将List进项拼接,并返回结果。
3.1.21 JZ33 丑数
思路:丑数能够分解成2^x3^y5^z,所以只需要把得到的丑数不断地乘以2、3、5之后并放入他们应该放置的位置即可。
(1)定义三个指针,分别代表2,3,5的个数
(2)每次取运算结果的最小值
3.1.22 JZ34 第一个只出现一次的字符
(1)定义一个包含所有字符的数组,ASCII码(一个ASCII码长度是一个字节,也就是8个bit,最高位是0作为校验位,其余7位使用0和1进行组合,所以ASCII码共有128个)
(2)遍历字符,将每个字符作为下标,将数组对应下标值加1
(3)遍历字符串,找到第一个数组值为1 的下标返回
3.1.23 JZ35 数组中的逆序对
思路:利用归并排序的过程求解
3.1.24 JZ37 数字在升序数组中出现的次数
思路:先利用二分查找找到该数的位置,再从该位置左右遍历相同的数并计数。
3.1.25 JZ40 数组中只出现一次的数字
思路:哈希表或异或运算
3.1.26 JZ41 和为S的连续正数序列
思路:穷举法,双层遍历,找到了就加入结果集。
3.1.27 JZ42 和为S的两个数字
思路:双指针法
(1)初始化双指针为一头一尾
(2)若当前两数和小于S,则左指针右移;若大于S,则右指针左移;否则,输出结果。
3.1.28 JZ43 左旋转字符串
思路一:利用标准库,s.substring()先进行字符串拆分,再进行拼接。
思路二:先转为字符数组,再借助辅助数组进行移位。
3.1.29 JZ44 翻转单词顺序列
思路:先利用str.split(" ")将字符串按照空格分割为字符串数组,再利用数组移位或者是栈进行翻转。
3.1.30 JZ45 扑克牌顺子
思路:
(1)先排序数组
(2)遍历数组,记录数组中0的个数和不同非0数字之间的差值
(3)根据0的个数和差值进行判断
3.1.31 JZ46 孩子们的游戏(圆圈中最后剩下的数)
思路:递归,当我们知道了 f(n - 1, m) 对应的答案 x 之后,我们也就可以知道,长度为 n 的序列最后一个删除的元素,应当是从 m % n 开始数的第 x 个元素。
public int LastRemaining_Solution(int n, int m) {
if (n <= 0 || m <= 0) return -1;
return n == 1 ? 0 : (LastRemaining_Solution(n - 1, m) + m) % n;
}
3.1.32 JZ47 求1+2+3+...+n
思路:递归
3.1.33 JZ48 不用加减乘除做加法
3.1.34 JZ49 把字符串转换成整数
思路:注意越界问题即可。用布尔值记录正负号,再逐位计算。
3.1.35 JZ50 数组中重复的数字
思路:利用set进行遍历即可
3.2 链表
3.2.1 JZ03 从尾到头打印链表
思路一:利用一个栈,将元素顺序倒置。
思路二:正序遍历并保存元素至链表,利用Collections.reverse(list)反转链表。
3.2.2 JZ14 链表中倒数第k个结点
思路:快慢指针,首先让快指针先行k步,然后让快慢指针每次同行一步,直到快指针指向空节点,慢指针就是倒数第K个节点。
3.2.3 JZ15 反转链表
3.2.4 JZ16 合并两个排序的链表
思路:归并排序
3.2.5 JZ25 复杂链表的复制
思路:利用Map集合存储<链表节点,新建节点>,再遍历链表,建立新建链表之间的关系。
3.2.6 JZ36 两个链表的第一个公共结点
思路:这道题默认无环
(1)都无环:得到两个链表的长度,长链先走,再和短链一起走
(2)都有环:
· 若入环点相同,同无环解法
· 若入环点不同,从一个入环点往下遍历,在碰到自己之前碰到了另一个入环点,则返回该入环点;否则无相交点
其他情况都无相交点。
3.3 二叉树
3.3.1 JZ04 重建二叉树
思路:递归。利用中序和前序中,根节点的位置进行划分左右子树。
3.3.2 JZ17 树的子结构
思路:递归,选中结点递归是否是子树,若不是子树,再递归选中结点的左右节点查找子树。
3.3.3 JZ18 二叉树的镜像
思路:递归,DFS,先交换左右节点,再继续递归左右子节点
3.3.4 JZ22 从上往下打印二叉树
思路:利用队列,层序遍历,BFS。
3.3.5 JZ23 二叉搜索树的后序遍历序列
思路:递归,根据元素大小进行左右递归分区,知道分区只剩一个元素或0个元素,往前返回。
3.3.6 JZ24 二叉树中和为某一值的路径
思路:回溯,每个元素先加入,若满足条件,加入结果集,再遍历左右子树,然后回溯。
3.3.7 JZ26 二叉搜索树与双向链表
思路:先中序遍历结果存储在链表中,再遍历链表,连接左右指针。
3.3.8 JZ38 二叉树的深度
思路:递归,递归过程中将左右子树的最大值加1;
3.3.9 JZ39 平衡二叉树
思路:递归,递归中判断左右字数高度差
4 JavaG
5 题目中的细节处理
5.1 在遍历中,对特殊值(特别是i = 0时的处理)
for(int i = 0; i < m; i++){
dp[i][0] = grid[i][0] + ( (i - 1 < 0)? 0: dp[i - 1][0]);
}
5.2 取字符串的子串
String s = "123";
s.substring(0,2); -->"12";
注意substring中没有单词大写!
5.3 取数组的子数组
Arrays.copyOfRange(arr,start,end);--> [start,end)
5.4 翻转链表
Collections.reverse(list);
5.5 Integer类型的最大值和最小值属性
int maxSum = Integer.MAX_VALUE;
int minSum = Integer.MIN_VALUE;
5.6 StringBuffer相关操作
(1)添加基础类型变量
strbuff.append(...)
(2)删除对应下标的字符
strbuff.deleteCharAt(index)
strbuff.delete(from, to)
(3)与String相同的API
strbuff.charAt(index)
strbuff.length()
strbuff.substring(from, to)(4)转换为String
strbuff.toString()
5.7 初始化基本类型数组
boolean[] used
Arrays.fill(used, false);
5.8 链表转为String
String.join(".", list)
5.9 字符串转整数
int a = Integer.valueOf(s.substring(i - 2, i))
5.10 字符串转字符数组
String s = "abc";
char[] arr = s.toCharArray();
5.11 Character相关API
Character.isLetterOrDigit('c');
Character.isDigit('1');
Character.isLetter('c');
Character.toLowerCase('C');
Character.toUpperCase('c');
5.12 字符串的trim方法
trim() 方法用于删除字符串的头尾空白符。public class Test {
public static void main(String args[]) {
String Str = new String(" https://blog.csdn.net/Mrs_chens ");
System.out.print("原始值 :" );
System.out.println( Str );
System.out.print("删除头尾空白 :" );
System.out.println( Str.trim() );
}
}
5.13 Arrays工具类中自带二分查找
int index = Arrays.binarySearch(array, target);
5.14 CompareTo方法
是String类中的方法