(Java版)剑指offer(一)

03.找数组中重复的数字
HashSet只能存储不重复的数据
把num放在HashSet中,可以存放表示没有重复,不能存放则表示重复

class Solution {
    public int findRepeatNumber(int[] nums) {
        HashSet set = new HashSet();
        int repeat  = -1;
        for(int num:nums){
            if(!set.add(num)){
                return repeat = num;
            }
        }
        return -1;
    }
}

04.二维数组中的查找
四个对角是该行或该列中的最小值和最大值,那么查找的方式定位到左上角或者右上角就是一种边形的二分查找形式。
如果从左下角出发,数组中的数大于target,可以下标向上整行移动,如果小于target,则索引下标往列移动。

class Solution {
    public boolean findNumberIn2DArray(int[][] matrix, int target) {
        int i = matrix.length - 1, j = 0; //从左下角开始,也可以从右上角开始,代码对应改动即可
        while(i >= 0 && j < matrix[0].length)
        {
            if(matrix[i][j] > target) i--;
            else if(matrix[i][j] < target) j++;
            else return true;
        }
        return false;
    }
}

05.替换空格
s字符串有多少个空格未知,所以字符序列长度不固定,使用StringBuffer或StringBuilder。直接调用StringBuffer的API下的append函数。
注意:方法是String类型的,所以return要做类型转换,valueOf

class Solution {
    public String replaceSpace(String s) {
        if(s == null) return s;
        StringBuffer  result = new StringBuffer();
        for(int i= 0;i<s.length();i++){
            if(s.charAt(i) == ' ')
                result.append("%20");
            else
                result.append(s.charAt(i));
        }
        return String.valueOf(result);//把stringbuffer 转为 string
    }
}```
06.从头到尾打印链表
 	翻转链表,栈是先进后出,利用栈辅助先把链表中节点的值入栈 ,再把栈元素依次弹出就是链表翻转后的值。
 

```cpp
class Solution {
    public int[] reversePrint(ListNode head) {
        Stack<ListNode> stack = new Stack<ListNode>();//可以用LinkList构造链表
        ListNode temp = head;
        while (temp != null) {
            stack.push(temp);
            temp = temp.next;
        }
        int size = stack.size();
        int[] print = new int[size];
        for (int i = 0; i < size; i++) {
            print[i] = stack.pop().val;
        }
        return print;
    }
}

07.重建二叉树
关键在如何利用前序遍历和中序遍历结果划分子树的根节点
用HashMap存储中序遍历的结果,每一次获取前序和中序相等时中序的value值,迭代递归每个子树。

class Solution {
    int[] preorder;
    HashMap<Integer, Integer> dic = new HashMap<>();
    public TreeNode buildTree(int[] preorder, int[] inorder) {
        this.preorder = preorder;;
        for(int i = 0; i < inorder.length; i++)
            dic.put(inorder[i], i);
        return recur(0, 0, inorder.length - 1);
    }
    TreeNode recur(int root, int left, int right) {
        if(left > right) return null;                          // 递归终止,只会执行一次
        TreeNode node = new TreeNode(preorder[root]);          // 建立根节点
        int i = dic.get(preorder[root]);                       // 划分根节点、左子树、右子树
        node.left = recur(root + 1, left, i - 1);              // 开启左子树递归 
        node.right = recur(root + i - left + 1, i + 1, right); // 开启右子树递归
        return node;                                           // 回溯返回根节点
    }
}

递归需要注意的地方,当第一个左子树递归结束之后会出现recur(2,0,-1),此时递归回溯到根结点,然后开启递归右子树。

09 用两个栈实现队列
实现队列的appendTail 和 deleteHead函数
栈可以用 LinkedList实现,,添加在stack1中完成,然后将stack1的值压入stack2.删除操作针对stack2完成。

class CQueue {
    Deque<Integer> stack1;
    Deque<Integer> stack2;
    public CQueue() {
        stack1 = new LinkedList<Integer>();
        stack2 = new LinkedList<Integer>();
    }
    
    public void appendTail(int value) {
        stack1.push(value);
    }
    
    public int deleteHead() {
        if(stack2.isEmpty()){
            while(!stack1.isEmpty()){
                stack2.push(stack1.pop());
            }
        }
        if(stack2.isEmpty()){
            return -1;
        }else{
            int deletitem = stack2.pop();
            return deletitem;
        }
    }
}

10-I.斐波拉契数列(考虑大数求余)的第n项
铭记大数越界求余法:x%1000000007

class Solution {
    public int fib(int n) {
        int a = 0, b = 1, sum;
        for(int i = 0; i < n; i++){
            sum = (a + b) % 1000000007;//大数越界取余方法
            a = b;
            b = sum;
        }
        return a;
    }
}	

如果想要返回值是b,则需要修改for里面的逻辑

10-II 青蛙跳台阶问题

class Solution {
//转化为斐波拉契数列求和
//最后一次跳台阶:
//		跳一级:前n-1个台阶有f(n-1)种跳法
//		跳两级:前n-2个台阶有f(n-2)种跳法
//f(n) = f(n-1) +f(n-2)
//f(0) =1;f(1) =1;f(2) = 2; 
    public int numWays(int n) {
        int a = 1,b= 1,sum =1;
        for(int i = 1; i < n; i++){
            sum = (a + b) % 1000000007;
            a = b;
            b = sum;
        }
        return sum;
    }
}

11.旋转数组的最小数字
本质为查找

class Solution {
    public int minArray(int[] numbers) {
        //二分法 注意等于的情况
        int i = 0, j = numbers.length - 1;
        while (i < j) {
            int m = (i + j) / 2;
            if (numbers[m] > numbers[j]) i = m + 1;
            else if (numbers[m] < numbers[j]) j = m; //等于的情况应另外分析
            else j--;//不能少
        }
        return numbers[i];
    }
}

12.矩阵中的路径
典型的dfs,注意如何进行剪枝

class Solution {
    public boolean exist(char[][] board, String word) {
        //深度优先搜索(DFS)+ 剪枝
        char[] words = word.toCharArray();
        for(int i = 0; i < board.length; i++) {
            for(int j = 0; j < board[0].length; j++) {
                if(dfs(board, words, i, j, 0)) return true;
            }
        }
        return false;
    }
    boolean dfs(char[][] board, char[] word, int i, int j, int k) {
        if(i >= board.length || i < 0 || j >= board[0].length || j < 0 || board[i][j] != word[k]) return false;
        if(k == word.length - 1) return true;
        board[i][j] = '\0';//标记已访问过的元素
        boolean res = dfs(board, word, i + 1, j, k + 1) || dfs(board, word, i - 1, j, k + 1) 
        || dfs(board, word, i, j + 1, k + 1) || dfs(board, word, i , j - 1, k + 1); //从四个方向进行递归,用或运算就表示剪枝
        board[i][j] = word[k];//存储已匹配的元素
        return res;
    }
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值