剑指Offer记录

First

十二月Flag

剑指Offer 快速刷一遍

Java基础

操作系统

乐优商场

十次方


剑指 Offer 06. 从尾到头打印链表

想到从尾到头,就要想到栈 的特点,后进先出,可以做倒置操作

剑指 Offer 25. 合并两个排序的链表

陷入了头节点的选择,应该想到可以制作伪头节点

剑指 Offer 46. 把数字翻译成字符串

难度中等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;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值