First
十二月Flag
剑指Offer 快速刷一遍
Java基础
操作系统
乐优商场
十次方
想到从尾到头,就要想到栈 的特点,后进先出,可以做倒置操作
陷入了头节点的选择,应该想到可以制作伪头节点
难度中等161
给定一个数字,我们按照如下规则把它翻译为字符串:0 翻译成 “a” ,1 翻译成 “b”,……,11 翻译成 “l”,……,25 翻译成 “z”。一个数字可能有多个翻译。请编程实现一个函数,用来计算一个数字有多少种不同的翻译方法。
示例 1:
输入: 12258
输出: 5
解释: 12258有5种不同的翻译,分别是"bccfi", "bwfi", "bczi", "mcfi"和"mzi"
这道题目很有意思
考察点: 动态规划、滚动数组
举个例子说明下递推方程的出现
12245
绝了我不会讲,但是拿出草稿纸可以说出来。。。。
此外还有滚动数组的问题,滚动数组就是三个数会一直往前移动,在移动过程中不断更新而已。
代码如下:
class Solution {
public int translateNum(int num) {
String str = String.valueOf(num);
//滚动变量
int pre = 1;
int mid = 1;
int nex = 1;
for(int i=1;i<str.length();i++){
int temp = (str.charAt(i-1)-'0')*10 + str.charAt(i)-'0';
if(temp>9 && temp <=25){
//可以被看作是其他数字
nex = pre + mid;
}else{
nex = mid;
}
pre = mid;
mid = nex;
}
return nex;
}
}
2021.1.20
剑指 Offer 04. 二维数组中的查找
这道题目就是典型的看懂题目隐藏的算法,就可以找到思路来做
简单的二叉搜索树
代码如下:
class Solution {
public boolean findNumberIn2DArray(int[][] matrix, int target) {
if(matrix.length == 0){
return false;
}
int w = matrix[0].length;
return findNum(matrix,0,w-1,target);
}
public boolean findNum(int[][] matrix,int i,int j,int target){
if(i<0 || i>=matrix.length || j<0){
return false;
}
if(matrix[i][j] == target){
return true;
}else if(matrix[i][j] <target){
return findNum(matrix,i+1,j,target);
}else{
return findNum(matrix,i,j-1,target);
}
}
}
剑指 Offer 07. 重建二叉树
这道题目真难
有一说一
我觉得这道题目需要深刻理解二叉树和递归
首先 左子树和右子树都是一棵树,可以看作新的递归方向
其次前序遍历和后序遍历的特点
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
//节省空间
private int[] preorder;
//做Map映射 保证在每次
private Map<Integer,Integer> map = new HashMap<>();
public TreeNode buildTree(int[] preorder, int[] inorder) {
this.preorder = preorder;
// 把那个map做好
for(int i=0;i<inorder.length;i++){
map.put(inorder[i],i);
}
return buTree(0,0,inorder.length-1);
}
public TreeNode buTree(int root,int left,int right){
//如何溢出
if(left > right){
return null;
}
TreeNode ro = new TreeNode(preorder[root]);
int i = map.get(preorder[root]);
//得到中序遍历的对应的根节点的位置
ro.left = buTree(root+1,left,i-1);
ro.right = buTree(root + i-left + 1,i+1,right);
return ro;
}
}
难点在于如何确定树
剑指 Offer 12. 矩阵中的路径
这道题目也挺难的
首先这是一个典型的矩阵搜索问题,可使用 深度优先搜索(DFS)+ 剪枝 解决。
矩阵搜索问题我最喜欢的是使用动态规划来写。
而这道题目需要使用DFS和剪枝操作。具体的操作方法看代码
class Solution {
private String word;
public boolean exist(char[][] board, String word) {
//做个防备
if(board.length == 0){
return false;
}
//做个dfs遍历
this.word = word;
for(int i=0;i<board.length;i++){
for(int j=0;j<board[0].length;j++){
//每一个都从新开始
if(dfs(board,i,j,0)==true){
return true;
}
}
}
return false;
}
public boolean dfs(char[][] board,int i,int j,int k){
//溢出条件
//溢出的时候需要考虑到输出false 和 true的条件
//两个都要考虑到
if(i<0||i>=board.length || j<0||j>=board[0].length || board[i][j]!=word.charAt(k)){
return false;
}
if(k == word.length()-1){
return true;
}
//首先我们把此次正确的位置标记
//其实说是剪枝 但是是在前置判断那里直接使得false了
board[i][j] = '\0';
boolean res = dfs(board,i-1,j,k+1)||dfs(board,i+1,j,k+1)||dfs(board,i,j-1,k+1)||dfs(board,i,j+1,k+1);
board[i][j] = word.charAt(k);
return res;
}
}
153. 寻找旋转排序数组中的最小值
这道题目使用二分查找的算法来做
但是有一些细节问题存在
比如right = mid;
这个地方
因为值可能在区间内部,所以在这种情况下不舍弃。
class Solution {
public int findMin(int[] nums) {
int left = 0;
int right = nums.length-1;
while(left<right){
int mid = left + (right-left)/2;
if(nums[mid]>nums[right]){
left = mid+1;
}else{
//如果是小于或者等于
//那么这个位置应该保留在区间里面
//因为这个值就是目标值!
right = mid;
}
}
return nums[left];
}
}
剑指 Offer 11. 旋转数组的最小数字
这道题目很经典
是二分查找的变种,建议再做几遍感受其中
class Solution {
public int minArray(int[] numbers) {
int left = 0;
int right = numbers.length-1;
while(left<right){
int mid = left + (right-left)/2;
if(numbers[mid] > numbers[right]){
left = mid + 1;
}else if(numbers[mid] < numbers[right]){
right = mid;
}else if(numbers[mid] == numbers[right]){
right-=1;
}
}
return numbers[left];
}
}
2021.1.22
剑指 Offer 68 - II. 二叉树的最近公共祖先
简单题
把具体情况列完整就好了
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if(root == p || root == q){
return root;
}
if(root == null){
return null;
}
TreeNode t1 = lowestCommonAncestor(root.left,p,q);
TreeNode t2 = lowestCommonAncestor(root.right,p,q);
if(t1!= null && t2 != null){
return root;
}
if(t1==null && t2 == null){
return null;
}
return t1==null?t2:t1;
}
}
剑指 Offer 68 - I. 二叉搜索树的最近公共祖先
简单题
也是利用一下二叉搜索树的特点就好了
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if(root == p || root ==q){
return root;
}
if(p.val>root.val && q.val>root.val){
return lowestCommonAncestor(root.right,p,q);
}else if(p.val<root.val && q.val<root.val){
return lowestCommonAncestor(root.left,p,q);
}else{
return root;
}
}
}
剑指 Offer 39. 数组中出现次数超过一半的数字
这道题目很有意思
利用一种对撞的想法
只要不相同就对撞,最后因为结果的个数大于一半
那么对撞到最后一定剩下我们需要的值
class Solution {
public int majorityElement(int[] nums) {
int vote = 1;
int x = nums[0];
for(int i=1;i<nums.length;i++){
if(vote==0){
x = nums[i];
vote++;
}else{
vote += nums[i]==x?1:-1;
}
}
return x;
}
}
剑指 Offer 21. 调整数组顺序使奇数位于偶数前面
这道题目,我一开始没写出来
说实话,还是太久没写过快慢指针的题目了
除了首尾指针之外,还有一种快慢指针的做法
两个指针一开始都在0位置
循环条件fast<nums.length
每一次循环判断是否该位置为奇数,如果是那么,两个位置互换
同时慢指针位置+1
*同时无论是否为奇数,快指针都+1*
首尾指针做法:
class Solution {
public int[] exchange(int[] nums) {
int left = 0;
int right = nums.length-1;
while(left<right){
while(left<nums.length&&nums[left]%2!=0){
left++;
}
while(right>=0&&nums[right]%2!=1){
right--;
}
if(left<right&&left!=nums.length&&right!=-1){
int temp = nums[left];
nums[left] = nums[right];
nums[right] = temp;
}
}
return nums;
}
}
快慢指针做法:
class Solution {
public int[] exchange(int[] nums) {
int fast = 0;
int low = 0;
while(fast<nums.length){
if(nums[fast]%2!=0){
int temp = nums[low];
nums[low] = nums[fast];
nums[fast] = temp;
low++;
}
fast++;
}
return nums;
}
}
剑指 Offer 61. 扑克牌中的顺子
这道题目让我很无语
大小王可以凑顺子???
那么如果可以凑顺子,我们分析一下
第一 牌不能重复
第二 很明显 大小王可以凑两张牌 那么最大3,4,5,6,7
7-3=4
小于5,就认为可以凑成顺子。
我觉得这种题目重点在于确定好他的结构
class Solution {
public boolean isStraight(int[] nums) {
//除了大小王 没有重复的
//最大值减去最小值小于5 那么大小王就可以帮助组合
Arrays.sort(nums);
int mi=0;
for(int i=0;i<4;i++){
if(nums[i]==0){
mi++;
}else if(nums[i]==nums[i+1]){
return false;
}
}
if(nums[4]-nums[mi]<5){
return true;
}
return false;
}
}
2021.1.23
今天电脑坏了。
血亏
2021.1.24
674. 最长连续递增序列
简单题目
class Solution {
public int findLengthOfLCIS(int[] nums) {
if(nums.length==0){
return 0;
}
int res = 0;
int nowRes=1;
for(int i=1;i<nums.length;i++){
if(nums[i]>nums[i-1]){
nowRes++;
}else{
res = res>nowRes?res:nowRes;
nowRes=1;
}
}
res = res>nowRes?res:nowRes;
return res;
}
}
剑指 Offer 29. 顺时针打印矩阵
这道题目很容易想
但是不好写
建议再写几遍
class Solution {
public int[] spiralOrder(int[][] matrix) {
if(matrix.length == 0) return new int[0];
int l = 0, r = matrix[0].length - 1, t = 0, b = matrix.length - 1, x = 0;
int[] res = new int[(r + 1) * (b + 1)];
while(true) {
for(int i = l; i <= r; i++) res[x++] = matrix[t][i]; // left to right.
if(++t > b) break;
for(int i = t; i <= b; i++) res[x++] = matrix[i][r]; // top to bottom.
if(l > --r) break;
for(int i = r; i >= l; i--) res[x++] = matrix[b][i]; // right to left.
if(t > --b) break;
for(int i = b; i >= t; i--) res[x++] = matrix[i][l]; // bottom to top.
if(++l > r) break;
}
return res;
}
}
剑指 Offer 59 - I. 滑动窗口的最大值
这道题目有暴力解法和非暴力解法
这里就写下暴力解法怎么写好了
class Solution {//模拟
public int[] maxSlidingWindow(int[] nums, int k) {
if(nums.length==0){
return new int[0];
}
int[] res = new int[nums.length-k+1];
int max = nums[0];
for(int i=1;i<k;i++){
max = max>nums[i]?max:nums[i];
}
res[0] = max;
for(int i=1;i<=nums.length-k;i++){
if(nums[i-1] == max){
//丢弃那么就需要重新找最值
max = nums[i];
for(int j=0;j<k;j++){
max = max>nums[i+j]?max:nums[i+j];
}
}else{
max = Math.max(max,nums[i+k-1]);
}
res[i] = max;
}
return res;
}
}
剑指 Offer 53 - I. 在排序数组中查找数字 I
这题不是很好写
有点烦,先这样。
2021.1.25
剑指 Offer 52. 两个链表的第一个公共节点
这道题目很有意思
重点在于如何理解清楚题目
emm直接代码展示
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
ListNode t1 = headA;
ListNode t2 = headB;
while(t1!=t2){
t1 = t1==null?headB:t1.next;
t2 = t2==null?headA:t2.next;
}
return t2;
}
}
剑指 Offer 50. 第一个只出现一次的字符
这道题目很明显的Hash表存储帮助
但是有一种hash表=>有序hash表
在java中的数据结构是LinkedHashMap
这种数据结构
在下一次的刷题中可以重点了解
下面是单纯HashMap方法
class Solution {
public char firstUniqChar(String s) {
Map<Character,Integer> map = new HashMap<>();
for(int i=0;i<s.length();i++){
map.put(s.charAt(i),map.getOrDefault(s.charAt(i),0)+1 );
}
for(int i=0;i<s.length();i++){
if(map.get(s.charAt(i))==1){
return s.charAt(i);
}
}
return ' ';
}
}
剑指 Offer 42. 连续子数组的最大和
这道题目标准的dp
但是不知道为什么我写的出错===
class Solution {
public int maxSubArray(int[] nums) {
int res = nums[0];
for(int i = 1; i < nums.length; i++) {
nums[i] += Math.max(nums[i - 1], 0);
res = Math.max(res, nums[i]);
}
return res;
}
}
剑指 Offer 18. 删除链表的节点
简单题目
只要知道如何删除节点和设置虚拟头节点规避风险就可以了
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode deleteNode(ListNode head, int val) {
ListNode Head = new ListNode(0);
Head.next = head;
ListNode pre = Head;
while(head!=null){
if(head.val==val){
pre.next = head.next;
break;
}
pre = head;
head = head.next;
}
return Head.next;
}
}
2021.1.26
剑指 Offer 28. 对称的二叉树
又TM是树—
真的无语,我感觉树就是看递归的思路够不够齐全
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public boolean isSymmetric(TreeNode root) {
if(root==null)
return true;
return isSymmetric2(root.left,root.right);
}
public boolean isSymmetric2(TreeNode left,TreeNode right){
if(left == null && right == null) return true;
if(left == null || right == null || left.val != right.val) return false;
return isSymmetric2(left.left,right.right)&&isSymmetric2(left.right,right.left);
}
}
剑指 Offer 55 - II. 平衡二叉树
这道题目有趣的点在于如何编造返回值
当我们把这个点搞定就很容易写出递归函数了
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public boolean isBalanced(TreeNode root) {
if(isBalanced2(root)!=-1){
return true;
}else{
return false;
}
}
public int isBalanced2(TreeNode root){
//溢出条件
if(root==null){
return 0;
}
//一旦存在不平衡 那么直接剪枝
int t1 = isBalanced2(root.left);
if(t1==-1){
return -1;
}
int t2 = isBalanced2(root.right);
if(t2==-1){
return -1;
}
if(Math.abs(t1-t2)>1){
return -1;
}else{
return Math.max(t1,t2)+1;
}
}
}
今天就先这样吧===
抱歉
2021.1.27
今日划水 我很抱歉
2021.1.28
随手做的每日一题
724. 寻找数组的中心索引
居然是使用前缀和来写
我本来想着使用双指针的方式来写,结果发现这样的写法似乎都得是正数才适合
所以下次在判断算法的时候,需要考虑到数的范围
class Solution {
public int pivotIndex(int[] nums) {
int totle = 0;
for(int i:nums){
totle+=i;
}
int sum=0;
for(int i=0;i<nums.length;i++){
if(sum*2+nums[i]==totle){
return i;
}
sum+=nums[i];
}
return -1;
}
}
剑指 Offer 64. 求1+2+…+n
好题目
我觉得中等题目更加考虑题目的深度和巧妙的运用逻辑
首先这种一般迭代、循环、递归等等
可是去除了那些语法,那么迭代和循环就不好使了
那么递归
正常的递归是这样的
class Solution {
public int sumNums(int n) {
if(n==1){
return 1;
}
return n + sumNums(n-1);
}
}
可是不能有if
,那么如何操作呢?
可以利用逻辑运算
所以有了
class Solution {
public int sumNums(int n) {
boolean x = n>0&&(n+=sumNums(n-1))>0;
return n;
}
}