《剑指Offer》刷题记

正则表达式匹配

时间限制:1秒 空间限制:32768K 热度指数:130667
本题知识点: 字符串

题目描述
请实现一个函数用来匹配包括’.‘和’‘的正则表达式。模式中的字符’.‘表示任意一个字符,而’'表示它前面的字符可以出现任意次(包含0次)。 在本题中,匹配是指字符串的所有字符匹配整个模式。例如,字符串"aaa"与模式"a.a"和"abaca"匹配,但是与"aa.a"和"ab*a"均不匹配

代码1

import java.util.*;
public class Solution {
    
    
    public boolean match(char[] str, char[] pattern)
    {
    
    
       return new String(str).matches(new String(pattern));
    }
}

代码2
特别注意:下面代码是用str去匹配pattern,匹配上了就把pattern往后移动继续匹配,直到把pattern匹配完的时候,如果str还是没用完,就说明根本匹配不成功,只有把pattern全都匹配完的时候用光了str才证明确实匹配成功了

public class Solution {
    public boolean match(char[] str, char[] pattern)
    {
       if(str == null || pattern == null){
           return false;
       }
       return match(str, 0, pattern, 0);
    }
    private boolean match(char[] str, int i, char[] pattern, int j){
        //特别注意这里:一定是判断pattern是否遍历完了
        if(pattern.length == j){
            return str.length == i;
        }
        //如果遇到*就是很特殊的情况了
        if(j < pattern.length - 1 && pattern[j+1] == '*'){
            if(i < str.length && (str[i] == pattern[j] || pattern[j] == '.')){
                //匹配上了,有两条路可以往后走!!这其实就是dfs暴力搜索啊
                return match(str, i, pattern, j+2) || match(str, i+1, pattern, j);
                
            }else{
                //没匹配上,那个*就代表其前面的字母使用0次
                return match(str, i, pattern, j+2);
            } 
        }
        
        //没遇到*就是最简单的了。
        if(i < str.length && (str[i] == pattern[j] || pattern[j] == '.')){
            return match(str, i+1, pattern, j+1);
        }
        return false;
    }
}

表示数值的字符串

时间限制:1秒 空间限制:32768K 热度指数:102727
本题知识点: 字符串

题目描述
请实现一个函数用来判断字符串是否表示数值(包括整数和小数)。例如,字符串"+100",“5e2”,"-123",“3.1416"和”-1E-16"都表示数值。 但是"12e",“1a3.14”,“1.2.3”,"±5"和"12e+4.3"都不是。

思路
按照整数、非科学计数法的小数和科学计数法的小数分三类讨论。

public class Solution {
    
    
    public boolean isNumeric(char[] str) {
    
    
        //简直了!!分类讨论。。。
        if(str == null){
    
    
            return false;
        }
        String s = new String(str);
        //如果头部有+、-,先去掉再说
        if(s.charAt(0) == '+' || s.charAt(0) == '-'){
    
    
            if(s.length() == 1){
    
    
                return false;
            }
            s = s.substring(1, s.length());
        }
        if(judge1(s) && (judge2(s) || judge3(s) || judge4(s))){
    
    
            return true;
        }
        return false;
    }
    //是否包含非法字符
    private boolean judge1(String str){
    
    
        if(str == ""){
    
    
            return false;
        }
        for(int i = 0; i < str.length(); i++){
    
    
            char c = str.charAt(i);
            if(!(c == '+' || c == '-' || c == 'e' || c == 'E' || c == '.' ||(c >= '0' && c <='9')
                )){
    
    
                return false;
            }
        }
        return true;
    }
    //是否是整数
    private boolean judge2(String str){
    
    
        for(int i = 0; i < str.length(); i++){
    
    
            char c = str.charAt(i);
            if(!(c >= '0' && c <= '9')){
    
    
                return false;
            }
        }
        return true;
    }
    //是否是非科学计数法的小数
    private boolean judge3(String str){
    
    
        if(str.indexOf(".") == -1){
    
    
            return false;
        }
        //找到小数点位置
        int loc = str.indexOf(".");
        
        //最后一个字符是小数点
        if(loc == str.length()-1){
    
    
            return false;
        }
        for(int i = 0; i < loc; i++){
    
    
            char c = str.charAt(i);
            if(!(c >= '0' && c <= '9')){
    
    
                return false;
            }
        }
        for(int i = loc + 1; i < str.length(); i++){
    
    
            char c = str.charAt(i);
            if(!(c >= '0' && c <= '9')){
    
    
                return false;
            }
        }
        return true;
    }
    //是否是科学计数法的小数
    private boolean judge4(String str){
    
    
        if(str.indexOf('e') == -1 && str.indexOf('E') == -1){
    
    
            return false;
        }
        //找到e/E的位置
        int loc = -1;
        for(int i = 0; i < str.length(); i++){
    
    
            char c = str.charAt(i);
            if(c == 'e' || c == 'E'){
    
    
                loc = i;
                break;
            }
        }
        if(loc == str.length()-1){
    
    
            return false;
        }
        //判一下e/E前后的字符串
        String s1 = str.substring(0, loc);
        String s2 = "";
        if(str.charAt(loc+1) == '+' || str.charAt(loc+1) == '-'){
    
    
            if(loc+1 == str.length()-1){
    
    
                return false;
            }
            s2 = str.substring(loc+2, str.length());
        }else{
    
    
            s2 = str.substring(loc+1, str.length());
        }
        if((judge2(s1) || judge3(s1)) && judge2(s2)){
    
    
            return true;
        }
        return false;
        
    }
}

机器人的运动范围

时间限制:1秒 空间限制:32768K 热度指数:112747

题目描述
地上有一个m行和n列的方格。一个机器人从坐标0,0的格子开始移动,每一次只能向左,右,上,下四个方向移动一格,但是不能进入行坐标和列坐标的数位之和大于k的格子。 例如,当k为18时,机器人能够进入方格(35,37),因为3+5+3+7 = 18。但是,它不能进入方格(35,38),因为3+5+3+8 = 19。请问该机器人能够达到多少个格子?

//DFS
public class Solution {
    
    
    public int movingCount(int threshold, int rows, int cols)
    {
    
    
        boolean[][] flag = new boolean[rows][cols];
        return solve(0, 0, rows, cols, threshold, flag);
    }
    private int solve(int i, int j, int rows, int cols, int threshold, boolean[][] flag){
    
    
        Integer ii = digitSum(i);
        Integer jj = digitSum(j);
        if(i < 0 || i >= rows || j < 0 || j >= cols || ii + jj > threshold || flag[i][j] == true){
    
    
            return 0;
        }
        flag[i][j] = true;
        return 1 + solve(i, j-1, rows, cols, threshold, flag) + 
            solve(i, j+1, rows, cols, threshold, flag) + 
            solve(i-1, j, rows, cols, threshold, flag) + 
            solve(i+1, j, rows, cols, threshold, flag);
    } 
    private int digitSum(int n){
    
    
        String s = n + "";
        int sum = 0;
        for(int i = 0; i < s.length(); i++){
    
    
            Integer x = s.charAt(i) - '0';
            sum += x;
        }
        return sum;
    }
}

矩阵中的路径

时间限制:1秒 空间限制:32768K 热度指数:122033

题目描述
请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。路径可以从矩阵中的任意一个格子开始,每一步可以在矩阵中向左,向右,向上,向下移动一个格子。如果一条路径经过了矩阵中的某一个格子,则之后不能再次进入这个格子。 例如 a b c e s f c s a d e e 这样的3 X 4 矩阵中包含一条字符串"bcced"的路径,但是矩阵中不包含"abcb"路径,因为字符串的第一个字符b占据了矩阵中的第一行第二个格子之后,路径不能再次进入该格子。

public class Solution {
    
    
    public boolean hasPath(char[] matrix, int rows, int cols, char[] str)
    {
    
    
        //回溯法
        boolean[] flag = new boolean[matrix.length];//引用类型的有默认初始化值
        for(int i = 0; i < rows; i++){
    
    
            for(int j = 0; j < cols; j++){
    
    
                if(check(matrix, rows, cols, i, j, flag, str, 0)){
    
    
                    return true;
                }
            }
        }
        return false;
    }
    public boolean check(char[] matrix, int rows, int cols, int i, int j, boolean[] flag, char[] str, int cnt){
    
    
        int index = i*cols + j;//二维与一维对应
        //递归结束(无法满足)
        if(i < 0 || i >= rows || j < 0 || j >= cols || flag[index] == true || matrix[index] != str[cnt]){
    
    
            return false;
        }
        //递归结束(满足)
        if(cnt == str.length -1){
    
    
            return true;
        }
        
        //递归不结束,走当前这一步
        flag[index] = true;
        
        //四个方向递归调用
        if(check(matrix, rows, cols, i-1, j, flag, str, cnt+1) ||
           check(matrix, rows, cols, i+1, j, flag, str, cnt+1) ||
           check(matrix, rows, cols, i, j-1, flag, str, cnt+1) ||
           check(matrix, rows, cols, i, j+1, flag, str, cnt+1)){
    
    
            return true;
        }
        
        //回溯(一旦此路不通,回去)
        flag[index] = false;
        return false;
    }


}

滑动窗口的最大值

时间限制:1秒 空间限制:32768K 热度指数:126716

题目描述
给定一个数组和滑动窗口的大小,找出所有滑动窗口里数值的最大值。例如,如果输入数组{2,3,4,2,6,2,5,1}及滑动窗口的大小3,那么一共存在6个滑动窗口,他们的最大值分别为{4,4,6,6,6,5}; 针对数组{2,3,4,2,6,2,5,1}的滑动窗口有以下6个: {[2,3,4],2,6,2,5,1}, {2,[3,4,2],6,2,5,1}, {2,3,[4,2,6],2,5,1}, {2,3,4,[2,6,2],5,1}, {2,3,4,2,[6,2,5],1}, {2,3,4,2,6,[2,5,1]}。

import java.util.*;
public class Solution {
    
    
    public ArrayList<Integer> maxInWindows(int [] num, int size)
    {
    
    
        ArrayList<Integer> list = new ArrayList<Integer>();
        if(num.length < size || num.length == 0 || size == 0){
    
    
            return list;
        }
        int l = 0;
        int r = l + size - 1;
        while(r <= num.length-1){
    
    
            int max = num[l];
            for(int i = l+1; i <= r; i++){
    
    
                if(num[i] > max){
    
    
                    max = num[i];
                }
            }
            l++;
            r++;
            list.add(max);
        }
        return list;
    }
}

数据流的中位数

时间限制:1秒 空间限制:32768K 热度指数:96416

题目描述
如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。我们使用Insert()方法读取数据流,使用GetMedian()方法获取当前读取数据的中位数。

import java.util.*;
public class Solution {
    
    
    private ArrayList<Integer> list = new ArrayList<Integer>();
    public void Insert(Integer num) {
    
    
        list.add(num);
    }

    public Double GetMedian() {
    
    
        int cnt = list.size();
        if(cnt == 0){
    
    
            return Double.valueOf(0);
        }
        list.sort(new Comparator<Integer>(){
    
    //注意这里加上泛型才能覆盖
            @Override
            public int compare(Integer a, Integer b){
    
    
                if(a < b){
    
    
                    return 1;
                }else if(a == b){
    
    
                    return 0;
                }else{
    
    
                    return -1;
                }
            }
        });
        if(cnt % 2 == 0){
    
    
            return Double.valueOf((list.get(cnt/2)+list.get(cnt/2-1)))/2;
        }else{
    
    
            return Double.valueOf((list.get(cnt/2)));
        }
    }


}

二叉搜索树的第k个节点

时间限制:1秒 空间限制:32768K 热度指数:143469

题目描述
给定一棵二叉搜索树,请找出其中的第k小的结点。例如, (5,3,7,2,4,6,8) 中,按结点数值大小顺序第三小结点的值为4。

/*
public class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;

    public TreeNode(int val) {
        this.val = val;

    }

}
*/
public class Solution {
    
    
    private int cnt = 0;
    TreeNode KthNode(TreeNode pRoot, int k)
    {
    
    
        //如果这棵树本身就是空的,就不用再找了。。
        if(pRoot == null){
    
    
            return null;
        }
        //二叉树中序遍历的第k个节点
        TreeNode node =  KthNode(pRoot.left, k);//从左子树找到第k个节点
        if(node != null){
    
    
            return node;
        }
        //左子树如果没找到第k个节点,看根是不是
        if(++cnt == k){
    
    
            return pRoot;
        }
        //如果左子树没找到,根也不是,看右子树能不能找到
        node = KthNode(pRoot.right, k);
        if(node != null){
    
    
            return node;
        }
        //如果左子树没找到,根也不是,右子树也没找到,那就找不到了。。。
        return null;
    }
}

序列化二叉树

序列化二叉树:把二叉树变成字符串
反序列化二叉树:根据字符串建立二叉树

时间限制:1秒 空间限制:32768K 热度指数:121974

题目描述
请实现两个函数,分别用来序列化和反序列化二叉树

/*
public class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;

    public TreeNode(int val) {
        this.val = val;

    }

}
*/
public class Solution {
    
    
    private int index = -1;
    String Serialize(TreeNode root) {
    
    
        String str = "";
        if(root == null){
    
    
            str += "#,";
            return str;
        }
        str += root.val + ",";
        str += Serialize(root.left);
        str += Serialize(root.right);
        return str;
  }
    TreeNode Deserialize(String str) {
    
    
       index++;
       String[] splits = str.split(",");
       TreeNode node = null;
       if(splits[index].equals("#") == false){
    
    
           node = new TreeNode(Integer.valueOf(splits[index]));
           node.left = Deserialize(str);
           node.right = Deserialize(str);
       }
       return node;
  }
}

把二叉树打印成多行

时间限制:1秒 空间限制:32768K 热度指数:101798

题目描述
从上到下按层打印二叉树,同一层结点从左至右输出。每一层输出一行。

思路

import java.util.ArrayList;


/*
public class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;

    public TreeNode(int val) {
        this.val = val;

    }

}
*/
import java.util.*;
public class Solution {
    public ArrayList<ArrayList<Integer> > Print(TreeNode pRoot) {
        //BFS
        ArrayList<ArrayList<Integer>> listAll = new ArrayList<ArrayList<Integer>>();
        if(pRoot == null){
            return listAll;
        }
        ArrayDeque<TreeNode> que = new ArrayDeque<TreeNode>();
        que.add(pRoot);
        while(que.isEmpty() == false){
            int size = que.size();
            ArrayList<Integer> list = new ArrayList<Integer>();
            for(int i = 0; i < size; i++){
                TreeNode node = que.remove();
                list.add(node.val);
                if(node.left != null){
                    que.add(node.left);
                }
                if(node.right != null){
                    que.add(node.right);
                }
            }
            listAll.add(list);
        }
        return listAll;
    }

}

按之字形顺序打印二叉树

时间限制:1秒 空间限制:32768K 热度指数:124380

题目描述
请实现一个函数按照之字形打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右至左的顺序打印,第三行按照从左到右的顺序打印,其他行以此类推。

思路
BFS。每次取出队列中所有节点,也就是树的一层

import java.util.ArrayList;

/*
public class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;

    public TreeNode(int val) {
        this.val = val;

    }

}
*/
import java.util.*;
public class Solution {
    
    
    public ArrayList<ArrayList<Integer> > Print(TreeNode pRoot) {
    
    
        //BFS
        ArrayList<ArrayList<Integer>> listAll = new ArrayList<ArrayList<Integer>>();
        if(pRoot == null){
    
    
            return listAll;
        }
        ArrayDeque<TreeNode> que = new ArrayDeque<TreeNode>();
        boolean flag = true;//用来标记奇数行和偶数行
        que.add(pRoot);
        while(que.isEmpty() == false){
    
    
            int size = que.size();
            ArrayList<Integer> list = new ArrayList<Integer>();
            for(int i = 0; i < size; i++){
    
    
                TreeNode node = que.remove();
                if(flag){
    
    
                    list.add(node.val);
                }else{
    
    
                    list.add(0, node.val);
                }
                if(node.left != null){
    
    
                    que.add(node.left);
                }
                if(node.right != null){
    
    
                    que.add(node.right);
                }
            }
            listAll.add(list);
            flag = !flag;
        }
        return listAll;
    }

}

对称二叉树

时间限制:1秒 空间限制:32768K 热度指数:111088

题目描述
请实现一个函数,用来判断一颗二叉树是不是对称的。注意,如果一个二叉树同此二叉树的镜像是同样的,定义其为对称的。

/*
public class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;

    public TreeNode(int val) {
        this.val = val;

    }

}
*/
public class Solution {
    
    
    boolean isSymmetrical(TreeNode pRoot)
    {
    
    
        return judge(pRoot, pRoot);
    }
    private boolean judge(TreeNode left, TreeNode right){
    
    
        if(left == null && right == null){
    
    
            return true;
        }
        if(left == null || right == null){
    
    
            return false;
        }
        if(left.val != right.val){
    
    
            return false;
        }
        return judge(left.left, right.right) && judge(right.left, left.right);
    }
}

二叉树的下一个节点

时间限制:1秒 空间限制:32768K 热度指数:115233

题目描述
给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针。

/*
public class TreeLinkNode {
    int val;
    TreeLinkNode left = null;
    TreeLinkNode right = null;
    TreeLinkNode next = null;

    TreeLinkNode(int val) {
        this.val = val;
    }
}
*/
public class Solution {
    
    
    public TreeLinkNode GetNext(TreeLinkNode pNode)
    {
    
    
        if(pNode == null){
    
    
            return pNode;
        }
        if(pNode.right != null){
    
    
            pNode = pNode.right;
            while(pNode.left != null){
    
    
                pNode = pNode.left;
            }
            return pNode;
        }
        while(pNode.next != null){
    
    
            if(pNode == pNode.next.left){
    
    
                return pNode.next;
            }
            pNode = pNode.next;
        }
        return null;
    }
}

删除链表中重复的节点

时间限制:1秒 空间限制:32768K 热度指数:226246
本题知识点: 链表

题目描述
在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针。 例如,链表1->2->3->3->4->4->5 处理后为 1->2->5

/*
 public class ListNode {
    int val;
    ListNode next = null;

    ListNode(int val) {
        this.val = val;
    }
}
*/
import java.util.*;
public class Solution {
    
    
    public ListNode deleteDuplication(ListNode pHead)
    {
    
    
        if(pHead == null || pHead.next == null){
    
    
            return pHead;
        }
        ListNode head = new ListNode(0);
        head.next = pHead;
        ListNode pre = head;
        ListNode last = head.next;
        
        while(last != null){
    
    
            if(last.next !=null && last.val == last.next.val){
    
    
                while(last.next !=null && last.val == last.next.val){
    
    
                    last = last.next;
                }
                pre.next = last.next;
                last = last.next;
            }else{
    
    
                pre = pre.next;
                last = last.next;
            }
        }
        return head.next;
        
    }
}

链表中环的入口节点

时间限制:1秒 空间限制:32768K 热度指数:132023
本题知识点: 链表

题目描述
给一个链表,若其中包含环,请找出该链表的环的入口结点,否则,输出null。

/*
 public class ListNode {
    int val;
    ListNode next = null;

    ListNode(int val) {
        this.val = val;
    }
}
*/
import java.util.*;
public class Solution {
    
    

    public ListNode EntryNodeOfLoop(ListNode pHead)
    {
    
    
        HashSet<ListNode> set = new HashSet<ListNode>();
        while(pHead != null){
    
    
            if(!set.add(pHead)){
    
    
                return pHead;
            }
            pHead =  pHead.next;
        }
        return null;
    }
}

字符流中第一个不重复的字符

时间限制:1秒 空间限制:32768K 热度指数:91819
本题知识点: 字符串

题目描述
请实现一个函数用来找出字符流中第一个只出现一次的字符。例如,当从字符流中只读出前两个字符"go"时,第一个只出现一次的字符是"g"。当从该字符流中读出前六个字符“google"时,第一个只出现一次的字符是"l"。
输出描述:
如果当前字符流没有存在出现一次的字符,返回#字符。

注意
要用LinkedHashMap,确保按照顺序进入map,然后找到当前第一个出现一次的字符

import java.util.*;

public class Solution {
    
    
    //Insert one char from stringstream
    private LinkedHashMap<Character, Integer> map = new LinkedHashMap<Character, Integer>(); 
        
    public void Insert(char ch)
    {
    
    
        if(map.containsKey(ch)){
    
    
            map.put(ch, map.get(ch)+1);
        }else{
    
    
            map.put(ch, 1);
        }
    }
  //return the first appearence once char in current stringstream
    public char FirstAppearingOnce()
    {
    
    
        Iterator it = map.entrySet().iterator();
        while(it.hasNext()){
    
    
            Map.Entry entry = (Map.Entry)it.next();
            Character key = (Character)entry.getKey();
            Integer value = (Integer)entry.getValue();
            if(value == 1){
    
    
                return key;
            }
        }
        return '#';
    }
}

构建乘积数组

时间限制:1秒 空间限制:32768K 热度指数:84483
本题知识点: 数组

题目描述
给定一个数组A[0,1,…,n-1],请构建一个数组B[0,1,…,n-1],其中B中的元素B[i]=A[0]A[1]…*A[i-1]A[i+1]…*A[n-1]。不能使用除法。

import java.util.ArrayList;
public class Solution {
    
    
    public int[] multiply(int[] A) {
    
    
        int[] B = new int[A.length];
        for(int i = 0; i < A.length; i++){
    
    
            int sum = 1;
            for(int j = 0; j < A.length; j++){
    
    
                if(j != i){
    
    
                    sum *= A[j];
                }
            }
            B[i] = sum;
        }
        return B;
    }
}

数组中重复的数字

时间限制:1秒 空间限制:32768K 热度指数:164725
本题知识点: 数组

题目描述
在一个长度为n的数组里的所有数字都在0到n-1的范围内。 数组中某些数字是重复的,但不知道有几个数字是重复的。也不知道每个数字重复几次。请找出数组中任意一个重复的数字。 例如,如果输入长度为7的数组{2,3,1,0,2,5,3},那么对应的输出是第一个重复的数字2。

import java.util.*;
public class Solution {
    
    
    // Parameters:
    //    numbers:     an array of integers
    //    length:      the length of array numbers
    //    duplication: (Output) the duplicated number in the array number,length of duplication array is 1,so using duplication[0] = ? in implementation;
    //                  Here duplication like pointor in C/C++, duplication[0] equal *duplication in C/C++
    //    这里要特别注意~返回任意重复的一个,赋值duplication[0]
    // Return value:       true if the input is valid, and there are some duplications in the array number
    //                     otherwise false
    public boolean duplicate(int numbers[],int length,int [] duplication) {
    
    
        if(numbers == null || numbers.length == 0){
    
    
            return false;
        }
        HashSet<Integer>set = new HashSet<Integer>();
        for(int i = 0; i < numbers.length; i++){
    
    
            if(!set.add(numbers[i])){
    
    
                duplication[0] = numbers[i];
                return true;
            }
        }
        return false;
    }
}

把字符串转成整数

时间限制:1秒 空间限制:32768K 热度指数:141595
本题知识点: 字符串

题目描述
将一个字符串转换成一个整数(实现Integer.valueOf(string)的功能,但是string不符合数字要求时返回0),要求不能使用字符串转换整数的库函数。 数值为0或者字符串不是一个合法的数值则返回0。

输入描述:
输入一个字符串,包括数字字母符号,可以为空

输出描述:
如果是合法的数值表达则返回该数字,否则返回0

示例
输入
+2147483647
1a33
输出
2147483647
0

public class Solution {
    
    
    public int StrToInt(String str) {
    
    
        if(str == null || str.length() == 0){
    
    
            return 0;
        }
        char cal = '+';
        if(str.charAt(0) == '+'){
    
    
            str = str.substring(1, str.length());
        }else if(str.charAt(0) == '-'){
    
    
            str = str.substring(1, str.length());
            cal = '-';
        }
        for(int i = 0; i < str.length()-1; i++){
    
    
            if(str.charAt(i) == '0'){
    
    
                str.substring(i+1, str.length());
            }else{
    
    
                break;
            }
        }
        for(int i = 0; i < str.length(); i++){
    
    
            if(!(str.charAt(i)>='0' && str.charAt(i)<='9')){
    
    
                return 0;
            }
        }
        int sum = 0;
        for(int i = 0; i < str.length(); i++){
    
    
            sum = sum*10 + (str.charAt(i)-'0');
        }
        if(cal == '-'){
    
    
            return -sum;
        }else{
    
    
            return sum;
        }
    }
}

不用加减乘除做加法

时间限制:1秒 空间限制:32768K 热度指数:83474

题目描述
写一个函数,求两个整数之和,要求在函数体内不得使用+、-、*、/四则运算符号

代码1:

public class Solution {
    public int Add(int num1,int num2) {
        return Integer.sum(num1, num2);
    }
}

代码2:

public class Solution {
    public int Add(int num1,int num2) {
        if(num1 > 0){
            while(num1-->0){
                num2++;
            }
        }else if(num1 < 0){
            while(num1++<0){
                num2--;
            }
        }
        return num2;
    }
}

代码3:

public class Solution {
    
    
    public int Add(int num1,int num2) {
    
    
        while(num1 != 0){
    
    
            int sum = num1 ^ num2;//相加,不考虑进位
            int carry = (num1 & num2) << 1;//仅用于进位
            num1 = carry;
            num2 = sum;
        }
        return num2;
    }
}

求1+2+3+……+n

题目描述
求1+2+3+…+n,要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句(A?B:C)。

public class Solution {
    
    
    public int Sum_Solution(int n) {
    
    
        int ans = n;
        boolean flag = (ans > 0) && (ans += Sum_Solution(n-1)) > 0;
        return ans;
    }
}

孩子们的游戏(圆圈中最后剩下的数)

时间限制:1秒 空间限制:32768K 热度指数:128897
本题知识点: 模拟

题目描述
每年六一儿童节,牛客都会准备一些小礼物去看望孤儿院的小朋友,今年亦是如此。HF作为牛客的资深元老,自然也准备了一些小游戏。其中,有个游戏是这样的:首先,让小朋友们围成一个大圈。然后,他随机指定一个数m,让编号为0的小朋友开始报数。每次喊到m-1的那个小朋友要出列唱首歌,然后可以在礼品箱中任意的挑选礼物,并且不再回到圈中,从他的下一个小朋友开始,继续0…m-1报数…这样下去…直到剩下最后一个小朋友,可以不用表演,并且拿到牛客名贵的“名侦探柯南”典藏版(名额有限哦!!_)。请你试着想下,哪个小朋友会得到这份礼品呢?(注:小朋友的编号是从0到n-1)

import java.util.*;
public class Solution {
    
    
    public int LastRemaining_Solution(int n, int m) {
    
    
        if(n<=0 || m<=0){
    
    
            return -1;
        }
        ArrayList<Integer> list = new ArrayList<Integer>();
        for(int i = 0; i < n; i++){
    
    
            list.add(i);
        }
        while(list.size()>1){
    
    
                for(int i = 1 ; i <= m-1; i++){
    
    
                list.add(list.get(0));
                list.remove(0);
            }
            list.remove(0);
        }
        return list.get(0);
    }
}

扑克牌顺子

时间限制:1秒 空间限制:32768K 热度指数:134044
本题知识点: 字符串

题目描述
LL今天心情特别好,因为他去买了一副扑克牌,发现里面居然有2个大王,2个小王(一副牌原本是54张_)…他随机从中抽出了5张牌,想测测自己的手气,看看能不能抽到顺子,如果抽到的话,他决定去买体育彩票,嘿嘿!!“红心A,黑桃3,小王,大王,方片5”,“Oh My God!”不是顺子…LL不高兴了,他想了想,决定大\小 王可以看成任何数字,并且A看作1,J为11,Q为12,K为13。上面的5张牌就可以变成“1,2,3,4,5”(大小王分别看作2和4),“So Lucky!”。LL决定去买体育彩票啦。 现在,要求你使用这幅牌模拟上面的过程,然后告诉我们LL的运气如何, 如果牌能组成顺子就输出true,否则就输出false。为了方便起见,你可以认为大小王是0。

import java.util.*;
public class Solution {
    
    
    public boolean isContinuous(int [] numbers) {
    
    
        //1.没有重复的
        //2.最大-最小<=4
        if(numbers == null || numbers.length != 5){
    
    
            return false;
        }
        HashSet<Integer> set = new HashSet<Integer>();
        int max = -1;
        int min = 14;
        for(int x : numbers){
    
    
            if(set.contains(x) && x != 0){
    
    
                return false;
            }
            
            if(x != 0){
    
    
                set.add(x);
                 max = Math.max(x, max);
                min = Math.min(x, min);
            }
           
        }
        if(max - min <= 4){
    
    
            return true;
        }
        return false;
    }
}

反转单词顺序列

时间限制:1秒 空间限制:32768K 热度指数:231435
本题知识点: 字符串

题目描述
牛客最近来了一个新员工Fish,每天早晨总是会拿着一本英文杂志,写些句子在本子上。同事Cat对Fish写的内容颇感兴趣,有一天他向Fish借来翻看,但却读不懂它的意思。例如,“student. a am I”。后来才意识到,这家伙原来把句子单词的顺序翻转了,正确的句子应该是“I am a student.”。Cat对一一的翻转这些单词顺序可不在行,你能帮助他么?

public class Solution {
    
    
    public String ReverseSentence(String str) {
    
    
        if(str == null || str.trim().equals("")){
    
    
            return str;
        }
        String[] strs = str.split(" ");
        String s = "";
        for(int i = strs.length-1; i >= 0; i--){
    
    
            
            s += strs[i]+" ";
        }
        return s.trim();
    }
}

左旋转字符串

时间限制:1秒 空间限制:32768K 热度指数:143913
本题知识点: 字符串

题目描述
汇编语言中有一种移位指令叫做循环左移(ROL),现在有个简单的任务,就是用字符串模拟这个指令的运算结果。对于一个给定的字符序列S,请你把其循环左移K位后的序列输出。例如,字符序列S=”abcXYZdef”,要求输出循环左移3位后的结果,即“XYZdefabc”。是不是很简单?OK,搞定它!

public class Solution {
    
    
    public String LeftRotateString(String str,int n) {
    
    
        if(str == null || str.length()<=1){
    
    
            return str;
        }
        int nn = n % str.length();
        String str1 = str.substring(0, nn);
        String str2 = str.substring(nn, str.length());
        return str2 + str1;
    }
}

和为S的两个数字

时间限制:1秒 空间限制:32768K 热度指数:153416

题目描述
输入一个递增排序的数组和一个数字S,在数组中查找两个数,使得他们的和正好是S,如果有多对数字的和等于S,输出两个数的乘积最小的。
输出描述:
对应每个测试案例,输出两个数,小的先输出。

import java.util.ArrayList;
public class Solution {
    
    
    public ArrayList<Integer> FindNumbersWithSum(int [] array,int sum) {
    
    
        ArrayList<Integer> list = new ArrayList<Integer>();
        if(array == null && array.length <= 1){
    
    
            return list;
        }
        for(int i = 0; i < array.length; i++){
    
    
            for(int j = i+1; j < array.length; j++){
    
    
                if(array[i]+array[j]==sum){
    
    
                    if(list.size() == 0){
    
    
                        list.add(array[i]);
                        list.add(array[j]);
                        break;
                    }
                    int mul1 = array[i]*array[j];
                    int mul2 = list.get(0) * list.get(1);
                    if(mul2 > mul1){
    
    
                        list.clear();
                        list.add(array[i]);
                        list.add(array[j]);
                    }
                    break;
                }
            }
        }
        return list;
    }
}

和为S的连续正数序列

时间限制:1秒 空间限制:32768K 热度指数:166504

题目描述
小明很喜欢数学,有一天他在做数学作业时,要求计算出9~16的和,他马上就写出了正确答案是100。但是他并不满足于此,他在想究竟有多少种连续的正数序列的和为100(至少包括两个数)。没多久,他就得到另一组连续正数和为100的序列:18,19,20,21,22。现在把问题交给你,你能不能也很快的找出所有和为S的连续正数序列? Good Luck!
输出描述:
输出所有和为S的连续正数序列。序列内按照从小至大的顺序,序列间按照开始数字从小到大的顺序

import java.util.ArrayList;
public class Solution {
    
    
    public ArrayList<ArrayList<Integer> > FindContinuousSequence(int sum) {
    
    
       //看到此题,立马想到的是滑动窗口
        ArrayList<ArrayList<Integer>> listAll = new ArrayList<ArrayList<Integer>>();
        
        int l = 1;
        int r = 2;
        while(l < r){
    
    
            int cur = (l+r)*(r-l+1)/2;
            if(cur > sum){
    
    
                l++;
            }else if(cur < sum){
    
    
                r++;
            }else{
    
    
                ArrayList<Integer> list = new ArrayList<Integer>();
                for(int i = l; i <= r; i++){
    
    
                    list.add(i);
                }
                listAll.add(list);
                l++;
            }
        }
        return listAll;
    }
}

数组中只出现一次的数字

时间限制:1秒 空间限制:32768K 热度指数:165317
本题知识点: 数组

题目描述
一个整型数组里除了两个数字之外,其他的数字都出现了偶数次。请写程序找出这两个只出现一次的数字。

//num1,num2分别为长度为1的数组。传出参数
//将num1[0],num2[0]设置为返回结果
import java.util.*;
public class Solution {
    public void FindNumsAppearOnce(int [] array,int num1[] , int num2[]) {
        HashMap<Integer, Integer>map = new HashMap<Integer, Integer>();
        for(int i = 0; i < array.length; i++){
            if(map.containsKey(array[i])){
                map.put(array[i], map.get(array[i])+1);
            }else{
                map.put(array[i], 1);
            }
        }
        Iterator it = map.entrySet().iterator();
        int cnt = 0;
        while(it.hasNext()){
            Map.Entry entry = (Map.Entry)it.next();
            Integer key = (Integer)entry.getKey();
            Integer value = (Integer)entry.getValue();
            if(value == 1 && cnt == 0){
                num1[0] = key;
                cnt++;
            }else if(value == 1 && cnt == 1){
                num2[0] = key;
                break;
            }
        }
    }
}

平衡二叉树

平衡二叉搜索树(Self-balancing binary search tree)又被称为AVL树(有别于AVL算法),且具有以下性质:它是一 棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。

时间限制:1秒 空间限制:32768K 热度指数:141430

题目描述
输入一棵二叉树,判断该二叉树是否是平衡二叉树。

注意
需要递归判定子树也是平衡二叉树

public class Solution {
    
    
    public boolean IsBalanced_Solution(TreeNode root) {
    
    
        if(root == null){
    
    
            return true;//
        }
        int leftDepth = treeDepth(root.left);
        int rightDepth = treeDepth(root.right);
        return (Math.abs(leftDepth-rightDepth) <= 1 && IsBalanced_Solution(root.left) && IsBalanced_Solution(root.right));
    }
    private int treeDepth(TreeNode root){
    
    
        if(root == null){
    
    
            return 0;
        }
        int leftDepth = treeDepth(root.left);
        int rightDepth = treeDepth(root.right);
        return Math.max(leftDepth, rightDepth)+1;
    }
}

二叉树的深度

时间限制:1秒 空间限制:32768K 热度指数:115503

题目描述
输入一棵二叉树,求该树的深度。从根结点到叶结点依次经过的结点(含根、叶结点)形成树的一条路径,最长路径的长度为树的深度。

/**
public class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;

    public TreeNode(int val) {
        this.val = val;

    }

}
*/

public class Solution {
    
    
    private int depth = 0;
    public int TreeDepth(TreeNode root) {
    
    
        if(root == null){
    
    
            return 0;
        }
        return Math.max(TreeDepth(root.left), TreeDepth(root.right))+1;
    }
    
}

数组中的逆序对

时间限制:2秒 空间限制:32768K 热度指数:228207
本题知识点: 数组

题目描述
在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数P。并将P对1000000007取模的结果输出。 即输出P%1000000007
输入描述:
题目保证输入的数组中没有的相同的数字

数据范围:

对于%50的数据,size<=10^4

对于%75的数据,size<=10^5

对于%100的数据,size<=2*10^5

示例1
输入
复制
1,2,3,4,5,6,7,0
输出
复制
7

思路
归并排序。特别注意数组两半,左边,右边都是从右到左比较判定,否则会重复记录

public class Solution {
    public int InversePairs(int [] array) {
        if(array == null || array.length <= 1){
            return 0;
        }
        //思路:归并排序
        int[] tmp = new int[array.length];
        return mergeSort(array, 0, array.length-1, tmp)%1000000007;
    }
    private int mergeSort(int[] a, int st, int en, int[] tmp){
        if(st >= en){
            return 0;
        }
        int mid = (st+en)/2;
        
        int leftCnt = mergeSort(a, st, mid, tmp)%1000000007;
        int rightCnt = mergeSort(a, mid+1, en, tmp)%1000000007;
        int left = mid;
        int right = en;
        int i = en;
        int cnt = 0;
        while(left >=st && right >= mid+1){
            if(a[left] > a[right]){
                tmp[i--] = a[left--];
                cnt = (cnt + right - mid)%1000000007;
            }else{
                tmp[i--] = a[right--];
            }
        }
        while(left >= st){
            tmp[i--] = a[left--];
        }
        while(right >= mid+1){
            tmp[i--] = a[right--];
        }
        for(int j = st; j <= en; j++){
            a[j] = tmp[j];
        }
        return (leftCnt + rightCnt + cnt)%1000000007;
    }
}

第一个只出现一次的字符

时间限制:1秒 空间限制:32768K 热度指数:200407
本题知识点: 字符串

题目描述
在一个字符串(0<=字符串长度<=10000,全部由字母组成)中找到第一个只出现一次的字符,并返回它的位置, 如果没有则返回 -1(需要区分大小写).

思路1(Map)

import java.util.*;
public class Solution {
    
    
    public int FirstNotRepeatingChar(String str) {
    
    
        HashMap<Character, Integer> map = new HashMap<Character, Integer>();
        for(int i = 0; i < str.length(); i++){
    
    
            if(map.containsKey(str.charAt(i))){
    
    
                map.put(str.charAt(i), map.get(str.charAt(i))+1);
            }else{
    
    
                map.put(str.charAt(i), 1);
            }
        }
        Iterator it = map.entrySet().iterator();
        Integer index = str.length();
        while(it.hasNext()){
    
    
            Map.Entry entry = (Map.Entry)it.next();
            Character key = (Character)entry.getKey();
            Integer value = (Integer)entry.getValue();
            if(value == 1){
    
    
                if(str.indexOf(key)<index){
    
    
                    index = str.indexOf(key);
                }
            }
        }
        if(index < str.length()){
    
    
            return index;
        }else{
    
    
            return -1;
        }
    }
}

思路2(ArrayList)

import java.util.*;
public class Solution {
    public int FirstNotRepeatingChar(String str) {
        ArrayList<Character> list = new ArrayList<Character>();
        ArrayList<Integer> index = new ArrayList<Integer>();
        for(int i = 0; i < str.length(); i++){
            Character c = str.charAt(i);
            if(list.contains(c)){
                int x = list.indexOf(c);
                int cnt = index.get(x);
                index.set(x, cnt+1);
            }else{
                list.add(c);
                index.add(1);
            }
        }
        for(int i = 0; i < index.size(); i++){
            if(index.get(i) == 1){
                return str.indexOf(list.get(i));
            }
        }
        return -1;
    }
}

丑数

时间限制:1秒 空间限制:32768K 热度指数:198085
本题知识点: 数组

题目描述
把只包含质因子2、3和5的数称作丑数(Ugly Number)。例如6、8都是丑数,但14不是,因为它包含质因子7。 习惯上我们把1当做是第一个丑数。求按从小到大的顺序的第N个丑数。

import java.util.*;

public class Solution {
    
    
    public int GetUglyNumber_Solution(int index) {
    
    

        //队列,类似广度优先搜索
        ArrayList<Integer> list = new ArrayList<Integer>();
        HashSet<Integer> set = new HashSet<Integer>();
        list.add(1);
        set.add(1);
        int v = 0;
        for(int i = 1; i <= index; i++){
    
    
            v = list.remove(0);
            if(!set.contains(2*v) && 2*v>0){
    
    //注意可能溢出!!!!下同
                list.add(2*v);
                set.add(2*v);
            }
            if(!set.contains(3*v) && 3*v>0){
    
    
                list.add(3*v);
                set.add(3*v);
            }
            if(!set.contains(5*v) && 5*v>0){
    
    
                list.add(5*v);
                set.add(5*v);
            }
            Collections.sort(list);
        }
        return v;
    }
}

把数组排成最小的数

时间限制:1秒 空间限制:32768K 热度指数:177103
本题知识点: 数组

题目描述
输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。例如输入数组{3,32,321},则打印出这三个数字能排成的最小数字为321323。


import java.util.Arrays;
import java.util.Comparator;
public class Solution {
    
    
    public String PrintMinNumber(int [] numbers) {
    
    
        
        String[] s = new String[numbers.length];
        for(int i = 0; i < numbers.length; i++){
    
    
            s[i] = numbers[i] + "";
        }
        Arrays.sort(s, new Comparator<String>(){
    
    
            public int compare(String s1, String s2){
    
    
                String str1 = s1 + s2;
                String str2 = s2 + s1;
                return str1.compareTo(str2);
            }
        });
        String obj = "";
        for(int i = 0; i < s.length; i++){
    
    
            obj += s[i];
        }
        return obj;
    }
}

从1到n整数中1出现次数

时间限制:1秒 空间限制:32768K 热度指数:133857

题目描述
求出113的整数中1出现的次数,并算出1001300的整数中1出现的次数?为此他特别数了一下1~13中包含1的数字有1、10、11、12、13因此共出现6次,但是对于后面问题他就没辙了。ACMer希望你们帮帮他,并把问题更加普遍化,可以很快的求出任意非负整数区间中1出现的次数(从1 到 n 中1出现的次数)。

思路1(暴力搜)

public class Solution {
    public int NumberOf1Between1AndN_Solution(int n) {
        //暴力搜索
        String str = null;
        int sum = 0;
        for(int i = 1; i <=n; i++){
            str = i + "";
            for(int j = 0; j < str.length(); j++){
                if(str.charAt(j) == '1'){
                    sum++;
                }
            }
        }
        return sum;
    }
}

思路2(暴力搜)

public class Solution {
    
    
    public int NumberOf1Between1AndN_Solution(int n) {
    
    
        //暴力搜索
        StringBuffer sb = new StringBuffer();
        int sum = 0;
        for(int i = 1; i <= n; i++){
    
    
            sb.append(i);
        }
        String str = sb.toString();
        for(int i = 0; i < str.length(); i++){
    
    
            if(str.charAt(i) == '1'){
    
    
                sum++;
            }
        }
        return sum;
    }
}

连续子数组的最大和

时间限制:1秒 空间限制:32768K 热度指数:176092
本题知识点: 数组

题目描述
HZ偶尔会拿些专业问题来忽悠那些非计算机专业的同学。今天测试组开完会后,他又发话了:在古老的一维模式识别中,常常需要计算连续子向量的最大和,当向量全为正数的时候,问题很好解决。但是,如果向量中包含负数,是否应该包含某个负数,并期望旁边的正数会弥补它呢?例如:{6,-3,-2,7,-15,1,2,2},连续子向量的最大和为8(从第0个开始,到第3个为止)。给一个数组,返回它的最大连续子序列的和,你会不会被他忽悠住?(子向量的长度至少是1)

public class Solution {
    
    
    public int FindGreatestSumOfSubArray(int[] array) {
    
    
        //动态规划
        //状态:dp[i]表示前i个元素最大的连续子序列的和
        //转移方程:dp[i][j] = max{array[i], dp[i-1]+array[i]}
       
        int[] dp = new int[array.length];
        int maximum = array[0];
        dp[0] = array[0];
        
        for(int i = 1; i < dp.length; i++){
    
    
            dp[i] = max(dp[i-1]+array[i], array[i]);
            maximum = max(dp[i], maximum);
        }
        return maximum;
    }
    private int max(int a, int b){
    
    
        if(a < b){
    
    
            return b;
        }else{
    
    
            return a;
        }
    }
    
}

数组中出现次数超过一半的数字

时间限制:1秒 空间限制:32768K 热度指数:248291
本题知识点: 数组

题目描述
数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。如果不存在则输出0。

import java.util.*;
public class Solution {
    
    
    public int MoreThanHalfNum_Solution(int [] array) {
    
    
        HashMap<Integer, Integer> map = new HashMap<Integer, Integer>();
        for(int i = 0; i < array.length; i++){
    
    
            if(map.containsKey(array[i])){
    
    
                map.put(array[i],map.get(array[i])+1);
            }else{
    
    
                map.put(array[i], 1);
            }
        }
        Iterator it = map.entrySet().iterator();
        while(it.hasNext()){
    
    
            Map.Entry entry = (Map.Entry)it.next();
            Integer key = (Integer)entry.getKey();
            Integer value = (Integer)entry.getValue();
            if(value>array.length/2){
    
    
                return key;
            }
        }
        return 0;
    }
}

字符串的排列

时间限制:1秒 空间限制:32768K 热度指数:284134
本题知识点: 字符串

题目描述
输入一个字符串,按字典序打印出该字符串中字符的所有排列。例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba。
输入描述:
输入一个字符串,长度不超过9(可能有字符重复),字符只包括大小写字母。

import java.util.ArrayList;
import java.util.Collections;
public class Solution {
    
    
    private ArrayList<String> list = new ArrayList<String>();
    public ArrayList<String> Permutation(String str) {
    
    
       if(str==null || str.length()==0){
    
    
           return list;
       }
       char[] s = str.toCharArray();
       dfs(s, 0);
       Collections.sort(list);
       return list;
    }
    public void dfs(char[] s, int index){
    
    
        if(index == s.length){
    
    
            if(list.contains(new String(s))){
    
    
                return;
            }else{
    
    
                list.add(new String(s));
            }
        }else{
    
    
            for(int i = index; i < s.length; i++){
    
    
                swap(s, i, index);//每次都会有i==index的情况,
                			//这个是先把以自己打头的打印一份,再让后面的字符打头
                dfs(s, index+1);
                swap(s, i, index);
            }
        }
        
    }
    public void swap(char[] s, int i, int j){
    
    
        char tmp = s[i];
        s[i] = s[j];
        s[j] = tmp;
    }
}

二叉搜索树和双向链表

时间限制:1秒 空间限制:32768K 热度指数:183079

题目描述
输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点,只能调整树中结点指针的指向。

/**
public class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;

    public TreeNode(int val) {
        this.val = val;

    }

}
*/
public class Solution {
    
    
    //中序遍历
    private TreeNode leftHead = null;//链表左头
    private TreeNode rightHead = null;//链表右头
    public TreeNode Convert(TreeNode pRootOfTree) {
    
    
        if(pRootOfTree == null){
    
    
            return null;
        }
        Convert(pRootOfTree.left);
        if(leftHead == null){
    
    //最左子节点会成为链表的左头
            leftHead = rightHead = pRootOfTree;
        }else{
    
    //在中序遍历的时候会一直向右边扩展链表
            rightHead.right = pRootOfTree;
            pRootOfTree.left = rightHead;
            rightHead = pRootOfTree;
        }
        Convert(pRootOfTree.right);
        return leftHead;
    }
}

复杂链表的复制

时间限制:1秒 空间限制:32768K 热度指数:258694
本题知识点: 链表

题目描述
输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针指向任意一个节点),返回结果为复制后复杂链表的head。(注意,输出结果中请不要返回参数中的节点引用,否则判题程序会直接返回空)

思路1
先把链表的各个节点都复制一遍,建立源节点和新节点的映射关系,然后把新节点都串起来就好了!!比较有技巧的一点是random必然指向的是链表中的某个节点,所以只需要通过map.get获取相应的新创建的节点即可。

/*
public class RandomListNode {
    int label;
    RandomListNode next = null;
    RandomListNode random = null;

    RandomListNode(int label) {
        this.label = label;
    }
}
*/

import java.util.*;
public class Solution {
    
    
    public RandomListNode Clone(RandomListNode pHead)
    {
    
    
        HashMap<RandomListNode, RandomListNode> map = new HashMap<RandomListNode, RandomListNode>();
        RandomListNode tmp = pHead;
        //先把链表的每个节点复制一份
        while(tmp != null){
    
    
            map.put(tmp, new RandomListNode(tmp.label));
            tmp = tmp.next;
        }
        tmp = pHead;
        RandomListNode head = map.get(pHead);
        //把复制的各个节点串成链表
        while(tmp != null){
    
    
            map.get(tmp).next = map.get(tmp.next);
            map.get(tmp).random = map.get(tmp.random);//random必定是链表中的某个节点
            tmp = tmp.next;
        }
        return head;
    }
}

思路2:递归(错误)
简单粗暴的递归方法是不可行的,因为random可能是两个节点互相指向对方,造成死递归循环

二叉树中和为某一值的路径

时间限制:1秒 空间限制:32768K 热度指数:262145

题目描述
输入一颗二叉树的跟节点和一个整数,打印出二叉树中结点值的和为输入整数的所有路径。路径定义为从树的根结点开始往下一直到叶结点所经过的结点形成一条路径。(注意: 在返回值的list中,数组长度大的数组靠前)

思路
dfs+回溯

import java.util.ArrayList;
/**
public class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;

    public TreeNode(int val) {
        this.val = val;

    }

}
*/


public class Solution {
    
    
    private ArrayList<ArrayList<Integer>> res = new ArrayList<ArrayList<Integer>>();
    private ArrayList<Integer> list = new ArrayList<Integer>();
    
    public ArrayList<ArrayList<Integer>> FindPath(TreeNode root,int target) {
    
    
        if(root == null) return res;
        path(root, target);
        return res;
    }
    
    private void path(TreeNode root, int target){
    
    
        list.add(root.val);
        if(root.val==target && root.left==null && root.right==null){
    
    
            res.add(new ArrayList<Integer>(list));
        }
        if(root.left != null){
    
    
            path(root.left, target-root.val);
        }
        if(root.right != null){
    
    
            path(root.right, target - root.val);
        }
        list.remove(list.size()-1);//回溯
        return;
    }
    
}

二叉搜索树的后序遍历

时间限制:1秒 空间限制:32768K 热度指数:294137

题目描述
输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则输出Yes,否则输出No。假设输入的数组的任意两个数字都互不相同。

思路
二叉搜索树后序遍历,最右边必然是根,左子树全部小于根,右子树全部大于等于根,由根找到右子树开始元素,判定右子树是否有元素小于等于根,再递归判定即可

public class Solution {
    
    
    public boolean VerifySquenceOfBST(int [] sequence) {
    
    
        //假定空数组返回false
        if(sequence == null || sequence.length == 0){
    
    
            return false;
        }
        return judge(sequence, 0, sequence.length-1);
    }
    
    public boolean judge(int[] a, int st, int en){
    
    
        //a[en]就是根
        if(st>=en){
    
    
            return true;
        }
        int i = st;
        //找到右子树的第一个元素
        while(i<=en && a[i]<a[en]){
    
    
            i++;
        }
        for(int j = i+1; j < en; j++){
    
    
            if(a[j]<a[en]){
    
    
                return false;
            }
        }
        return judge(a, st, i-1) && judge(a, i, en-1);
    }
}

数字在排序数组中出现的次数

时间限制:1秒 空间限制:32768K 热度指数:172001
本题知识点: 数组

题目描述
统计一个数字在排序数组中出现的次数。

public class Solution {
    
    
    public int GetNumberOfK(int [] array , int k) {
    
    
        int loc = bi(array, k);
        if(loc == -1){
    
    
            return 0;
        }else{
    
    
            int sum = 0;
            for(int i = loc+1; i < array.length; i++){
    
    
                if(array[i] == k){
    
    
                    sum++;
                }else{
    
    
                    break;
                }
            }
            for(int i = loc-1; i >= 0; i--){
    
    
                if(array[i]==k){
    
    
                    sum++;
                }else{
    
    
                    break;
                }
            }
            return sum+1;
        }
        
    }
    
    public int bi(int[] array, int k){
    
    
        int l = 0;
        int r = array.length-1;
        while(l <= r){
    
    
            int mid = (l+r)/2;
            if(array[mid]==k){
    
    
                return mid;
            }else if(array[mid]>k){
    
    
                r = mid - 1;
            }else{
    
    
                l = mid + 1;
            }
        }
        return -1;
    }
}

最小的K个数

时间限制:1秒 空间限制:32768K 热度指数:317764
本题知识点: 数组

题目描述
输入n个整数,找出其中最小的K个数。例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4,。

import java.util.ArrayList;
public class Solution {
    
    
    public ArrayList<Integer> GetLeastNumbers_Solution(int [] input, int k) {
    
    
        ArrayList<Integer> list = new ArrayList<Integer>();
        if(k>input.length){
    
    
            return list;
        }
        java.util.Arrays.sort(input);
        for(int i = 0; i < k; i++){
    
    
            list.add(input[i]);
        }
        return list;
    }
}

两个链表的第一个公共节点

时间限制:1秒 空间限制:32768K 热度指数:153107
本题知识点: 链表

题目描述
输入两个链表,找出它们的第一个公共结点。

/*
public class ListNode {
    int val;
    ListNode next = null;

    ListNode(int val) {
        this.val = val;
    }
}*/
public class Solution {
    
    
    public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) {
    
    
        ListNode common = null;
        if(pHead1==null || pHead2==null){
    
    
            return common;
        }
        while(pHead1!= null){
    
    
            ListNode tmp = pHead2;
            while(tmp!=null){
    
    
                if(tmp.val == apHead1.val){
    
    
                    return tmp;
                }
                tmp = tmp.next;
            }
            pHead1 = pHead1.next;
        }
        return common;
    }
}

从上往下打印二叉树

时间限制:1秒 空间限制:32768K 热度指数:261102

题目描述
从上往下打印出二叉树的每个节点,同层节点从左至右打印。

思路
层次遍历/宽度优先搜索,队列模拟

import java.util.ArrayList;
import java.util.ArrayDeque;
/**
public class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;

    public TreeNode(int val) {
        this.val = val;

    }

}
*/
public class Solution {
    
    
    public ArrayList<Integer> PrintFromTopToBottom(TreeNode root) {
    
    
        
        ArrayList<Integer> list = new ArrayList<Integer>();
        if(root == null){
    
    
            return list;
        }
        ArrayDeque<TreeNode> queue = new ArrayDeque<TreeNode>();
        queue.add(root);
        while(!queue.isEmpty()){
    
    
            TreeNode node = queue.remove();
            list.add(node.val);
            if(node.left != null){
    
    
                queue.add(node.left);
            }
            if(node.right != null){
    
    
                queue.add(node.right);
            }
        }
        return list;
    }
}

栈的压入、弹出序列

时间限制:1秒 空间限制:32768K 热度指数:248635
本题知识点: 栈

题目描述
输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈序列对应的一个弹出序列,但4,3,5,1,2就不可能是该压栈序列的弹出序列。(注意:这两个序列的长度是相等的)

思路
模拟入栈出栈过程即可

import java.util.ArrayList;
import java.util.Stack;

public class Solution {
    
    
    public boolean IsPopOrder(int [] pushA,int [] popA) {
    
    
        Stack<Integer> stack = new Stack<Integer>();
        for(int i = 0, j = 0; i < popA.length; i++){
    
    
            stack.push(pushA[i]);
            while(j < popA.length && stack.peek()==popA[j]){
    
    
                stack.pop();
                j++;
            }
        }
        return stack.empty();
    }
}

包含MIN函数的栈

时间限制:1秒 空间限制:32768K 热度指数:207928
本题知识点: 栈

题目描述
定义栈的数据结构,请在该类型中实现一个能够得到栈中所含最小元素的min函数(时间复杂度应为O(1))。

思路
开一个辅助栈stack2,用来存放最小元素的

import java.util.Stack;

public class Solution {
    
    
    private Stack<Integer> stack1 = new Stack<Integer>();
    private Stack<Integer> stack2 = new Stack<Integer>();
    
    
    public void push(int node) {
    
    
        stack1.push(node);
        if(stack2.empty()){
    
    
            stack2.push(node);
        }else{
    
    
            if(node < stack2.peek()){
    
    
                stack2.push(node);
            }
        }
    }
    
    public void pop() {
    
    
        if(stack1.empty()){
    
    
            
        }else{
    
    
            if(stack1.peek() == stack2.peek()){
    
    
                stack2.pop();
            }
            stack1.pop();
        }
    }
    
    public int top() {
    
    //这里有bug,栈有可能为空
        return stack1.peek();
    }
    
    public int min() {
    
    //这里有bug,栈可能为空
        return stack2.peek();
    }
}

顺时针打印矩阵

时间限制:1秒 空间限制:32768K 热度指数:352727
本题知识点: 数组

题目描述
输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字,例如,如果输入如下4 X 4矩阵: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 则依次打印出数字1,2,3,4,8,12,16,15,14,13,9,5,6,7,11,10.

思路
思想来自蛇形填数

import java.util.ArrayList;

public class Solution {
    
    
    public static ArrayList<Integer> printMatrix(int [][] matrix) {
    
    
        if(matrix == null){
    
    
            return null;
        }
        int row = matrix.length;//矩阵行数
        int col = matrix[0].length;//矩阵列数
        boolean[][] a = new boolean[row][col];//标记数组
        for(int i = 0; i < row; i++){
    
    
	        for(int j = 0; j< col ; j++){
    
    
		        a[i][j] = false;
		    }
	    }
        ArrayList<Integer> list = new ArrayList<Integer>();
        int x = 0;
        int y = 0;
        int cnt = 0;
        list.add(matrix[0][0]);
        a[0][0]=true;
        while(cnt<=col*row){
    
    
            //右走
            while(y<col-1  && !a[x][y+1]){
    
    
                list.add(matrix[x][++y]);
                a[x][y] =true;
                cnt++;
            }
           
            //下走
            while(x<row-1  && !a[x+1][y]){
    
    
                list.add(matrix[++x][y]);
                a[x][y] = true;
                cnt++;
            }
          
            //左走
            while(y>0 && !a[x][y-1]){
    
    
                list.add(matrix[x][--y]);
                a[x][y] = true;
                cnt++;
            }
           
            //上走
            while( x>0 && !a[x-1][y]){
    
    
                list.add(matrix[--x][y]);
                a[x][y] = true;
                cnt++;
            }
            cnt++;
        }
        return list;
    }
}

二叉树的镜像

时间限制:1秒 空间限制:32768K 热度指数:197550

题目描述
操作给定的二叉树,将其变换为源二叉树的镜像。
输入描述:二叉树的镜像定义:源二叉树8/  6   10/ \  / 5  7 9 11镜像二叉树8/  10   6/ \  / 11 9 7  5

思路
递归交换左右子树即可,必须是先序遍历或后序列遍历。

代码一(后序遍历):

/**
public class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;

    public TreeNode(int val) {
        this.val = val;

    }

}
*/
public class Solution {
    
    
    public void Mirror(TreeNode root) {
    
    
        if(root != null){
    
    
            Mirror(root.left);
            Mirror(root.right);
            TreeNode tmp = root.left;
            root.left = root.right;
            root.right = tmp;
        }
    }
}

代码二(先序遍历):

/**
public class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;

    public TreeNode(int val) {
        this.val = val;

    }

}
*/
public class Solution {
    
    
    public void Mirror(TreeNode root) {
    
    
        if(root != null){
    
    
            TreeNode tmp = root.left;
            root.left = root.right;
            root.right = tmp;
            Mirror(root.left);
            Mirror(root.right);
            
        }
    }
}

树的子结构

时间限制:1秒 空间限制:32768K 热度指数:335840

题目描述
输入两棵二叉树A,B,判断B是不是A的子结构。(ps:我们约定空树不是任意一个树的子结构)

思路
按照题目要求,如果root1和root2有一个为空树,就无法匹配,然后得先找到第一个值相等的节点,以这个节点为新树根,进行匹配,匹配不上,就试试母树的左子树,还匹配不上,就再试试母树的右子树,递归匹配下去即可。

/**
public class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;

    public TreeNode(int val) {
        this.val = val;

    }

}
*/
public class Solution {
    
    
    public boolean HasSubtree(TreeNode root1,TreeNode root2) {
    
    
        boolean flag = false;
        if(root1 != null && root2 != null){
    
    
            //只有root1和root2都非空的时候才会进行此方法执行
            
            //只有root1.val==root2.val的时候才会开始递归判定
            if(root1.val == root2.val){
    
    
                flag = isSub(root1, root2);
            }
            if(flag == false){
    
    
                //没有匹配上,就往左子树试试匹配
                flag = HasSubtree(root1.left, root2);
            }
            if(flag == false){
    
    
                //左子树仍然没有匹配上,就往右子树试试匹配
                flag = HasSubtree(root1.right, root2);
            }
        }
        return flag;
    }
    
    public boolean isSub(TreeNode root1,TreeNode root2){
    
    
        
        //当root2空的时候,无论root1是否空,都匹配成功
        if(root2 == null){
    
    
            return true;
        }
        //当root2非空的时候,如果root1已空,不可能匹配上
        if(root1 == null && root2 != null){
    
    
            return false;
        }
        //当root2非空,如果root1非空,要继续判定值是否相等,如果值不等,不能匹配上
        if(root1.val != root2.val){
    
    
            return false;
        }
        //当root2非空,如果root1非空,要继续判定值是否相等,如果值相等,需要继续递归判定
        return isSub(root1.left, root2.left) && isSub(root1.right, root2.right);
    }

}

合并两个有序链表

时间限制:1秒 空间限制:32768K 热度指数:347558
本题知识点: 链表

题目描述
输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则。

思路
归并排序思想,参考一下这篇博文

/*
public class ListNode {
    int val;
    ListNode next = null;

    ListNode(int val) {
        this.val = val;
    }
}*/
public class Solution {
    
    
    public ListNode Merge(ListNode list1,ListNode list2) {
    
    
        ListNode head = new ListNode(0);
       
        ListNode cur = head;
        while(list1 != null && list2 != null){
    
    
            if(list1.val < list2.val){
    
    
                cur.next = list1;
                list1 = list1.next;
            }else{
    
    
                cur.next = list2;
                list2 = list2.next;
            }
            cur = cur.next;
        }
        while(list1 != null){
    
    
            cur.next = list1;
            cur = cur.next;
            list1 = list1.next;
        }
        while(list2 != null){
    
    
            cur.next = list2;
            cur = cur.next;
            list2 = list2.next;
        }
        cur.next = null;
        return head.next;
    }
}

反转链表

时间限制:1秒 空间限制:32768K 热度指数:365720
本题知识点: 链表

题目描述
输入一个链表,反转链表后,输出新链表的表头。

思路
见代码

/*
public class ListNode {
    int val;
    ListNode next = null;

    ListNode(int val) {
        this.val = val;
    }
}*/
public class Solution {
    
    
    public ListNode ReverseList(ListNode head) {
    
    
        ListNode next = null;
        ListNode cur = head;
        ListNode last = null;
        while(cur!=null){
    
    
            next = cur.next;
            cur.next = last;
            last = cur;
            cur = next;
        }
        return last;
    }
}

链表中倒数第K个节点

时间限制:1秒 空间限制:32768K 热度指数:502784
本题知识点: 链表

题目描述
输入一个链表,输出该链表中倒数第k个结点。

思路
先计算链表总数,转换成正数第几个节点再找

/*
public class ListNode {
    int val;
    ListNode next = null;

    ListNode(int val) {
        this.val = val;
    }
}*/
public class Solution {
    
    
    public ListNode FindKthToTail(ListNode head,int k) {
    
    
        ListNode kNode = head;
        int sum = 0;//总节点数
        while(kNode!=null){
    
    
            kNode = kNode.next;
            sum++;
        }
        if(k>sum){
    
    
            return null;
        }
        int cnt = sum - k + 1;
        kNode = head;
        while(cnt>1){
    
    
            kNode = kNode.next;
            cnt--;
        }
        return kNode;
    }
}

调整数组顺序使奇数位于偶数前面

时间限制:1秒 空间限制:32768K 热度指数:359991
本题知识点: 数组

题目描述
输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分,所有的偶数位于数组的后半部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变。

思路
浪费空间实现,开两个数组,分别存放奇数和偶数

public class Solution {
    
    
    public void reOrderArray(int [] array) {
    
    
        int[] a = new int[array.length];
        int[] b = new int[array.length];
        int aLen = 0;
        int bLen = 0;
        for(int i = 0; i < array.length; i++){
    
    
            if(array[i]%2 != 0){
    
    
                a[aLen++] = array[i];
            }else{
    
    
                b[bLen++] = array[i];
            }
        }
        for(int i = 0; i < aLen; i++){
    
    
            array[i] = a[i];
        }
        for(int i = 0; i < bLen; i++){
    
    
            array[aLen+i] = b[i];
        }
    }
}

数值的整数次方

时间限制:1秒 空间限制:32768K 热度指数:307611

题目描述
给定一个double类型的浮点数base和int类型的整数exponent。求base的exponent次方。

思路1:调用Java的API


public class Solution {
    
    
    public double Power(double base, int exponent) {
    
    
        return (Math.pow(base,exponent));
  }
}

思路2:暴力连乘


public class Solution {
    
    
    public double Power(double base, int exponent) {
    
    
        double result = base;
        if(exponent == 0){
    
    
            return 1.0;
        }else if(exponent > 0){
    
    
            for(int i = 0; i < exponent-1; i++){
    
    
                result *= base;
            }
            return result;
        }else{
    
    
            for(int i = 0; i < -exponent-1; i++){
    
    
                result *= base;
            }
            return 1.0/result;
        }
  }
}

二进制中1的个数

时间限制:1秒 空间限制:32768K 热度指数:298520

题目描述
输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。

注意
题目说的不太明确,确切的说应该是对一个整数来说,在32位计算机中存储的补码形式中1的个数。也就是说一定要把一个数化为32位的二进制补码。。

思路1:移位和1与运算,对每一位进行判断是0还是1。

public class Solution {
    
    
    public int NumberOf1(int n) {
    
    
        int sum = 0;
        for(int i = 0; i < 32; i++){
    
    
            if((n>>i & 1) == 1){
    
    
                sum++;
            }
        }
        return sum;
    }
}

思路2:调用Java的API

public class Solution {
    
    
     public int NumberOf1(int n) {
    
    
         return Integer.bitCount(n);
	}
}

思路3:调用Java的API

public class Solution {
    
    
     public int NumberOf1(int n) {
    
    
         String str = Integer.toBinaryString(n);
         int sum = 0;
         for(int i = 0; i < str.length(); i++){
    
    
             if(str.charAt(i) == '1'){
    
    
                 sum++;
             }
         }
         return sum;
	}
}

思路4:利用整数二进制补码的求法求解
(笔者觉得思路可以,但通不过。。)

public class Solution {
    
    
     public static int NumberOf1(int n) {
    
    
	        int[] a = new int[33];
	        int cnt = 0;
	        int sum = 0;
	        int nn = n;
	        if(n<0){
    
    
	            nn = -n;
	        }
	        while(nn>0){
    
    
	            a[cnt] = nn%2;
	            if(a[cnt]==1){
    
    
	                sum++;
	            }
	            cnt++;
	            nn /= 2;
	        }
	        if(n>=0){
    
    
	            return sum;
	        }else{
    
    
	            sum = 0;
	            for(int i = 0; i <= 30; i++){
    
    
	                if(i>=cnt){
    
    
	                    a[i] = 0;
	                }
	                if(a[i] == 1){
    
    
	                    a[i] = 0;
	                }else{
    
    
	                    a[i] = 1;
	                }
	            }
	            a[0] += 1;
	            a[31] = 1;
	            for(int i = 0; i <= 31; i++){
    
    
	                if(a[i] >= 2){
    
    
	                    a[i] -= 2;
	                    a[i+1] += 1;
	                }
	                if(a[i] == 1){
    
    
	                    sum++;
	                }
	            }
	            return sum;
	        }
	    }
}

矩阵覆盖

时间限制:1秒 空间限制:32768K 热度指数:223823

题目描述
我们可以用21的小矩形横着或者竖着去覆盖更大的矩形。请问用n个21的小矩形无重叠地覆盖一个2*n的大矩形,总共有多少种方法?

思路
分析情况如下:当n=1,2,3的时候是3种不一样的情况,n>=4的时候可以迭代(递归)了。然后发现了递归规律,其实考虑的还是最后一次放矩形的i情况就是这三种之一了!然后递归就发现是斐波那契数列了,n=3的时候也适合,那就可以简化下了。。
在这里插入图片描述

public class Solution {
    
    
    public int RectCover(int target) {
    
    
        if(target < 0) return 0;//这个题目太坑了,竟然还让判断这个。。。
        if(target == 1){
    
    
            return 1;
        }else if(target == 2){
    
    
            return 2;
        }else{
    
    
            return RectCover(target-1)+RectCover(target-2);
        }
    }
}

变态跳台阶

时间限制:1秒 空间限制:32768K 热度指数:248187

题目描述
一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个n级的台阶总共有多少种跳法。

代码一(递归):

public class Solution {
    
    
    public int JumpFloorII(int target){
    
    
        if(target == 0){
    
    
            return 1;
        }else{
    
    
            int n = target;
            int sum = 0;
            for(int i = 1; i <= n; i++){
    
    
                if(n-i>=0){
    
    //注意这里是>=0
                    sum += JumpFloorII(n-i);
                }else{
    
    
                    break;
                }
            }
            return sum;
        }
    }
}

代码二(推公式);
仍然是逆向考虑,最后一次跳级必然是1、2、3……n级,那么f(n)=1+f(n-1)+f(n-2)+……+f(1),那么把n换成n+1,有f(n+1)=1+f(n)+f(n-1)+……+f(1),两式相减得到f(n+1)-f(n)=f(n),即f(n+1)=2*f(n),由于f(1)=1,那么f(n)=2^(n-1)

public class Solution {
    
    
    public int JumpFloorII(int target) {
    
    
        if(target == 1){
    
    
            return 1;
        }else{
    
    
            return 2*JumpFloorII(target-1);
        }
    }
}

public class Solution {
    
    
    public int JumpFloorII(int target){
    
    
        return 1<<(--target);
    }
}

跳台阶

时间限制:1秒 空间限制:32768K 热度指数:314942

题目描述
一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法(先后次序不同算不同的结果)。

思路
逆向思维,最后一级要么跳1级,要么跳2级。其实发现还是斐波那契数列的应用!

代码示范1:

public class Solution {
    
    
    public int JumpFloor(int target) {
    
    
        //关键:最后一次要么跳一级,要么跳2级
        if(target == 1){
    
    
            return 1;
        }else if(target == 2){
    
    
            return 2;
        }else{
    
    
            return JumpFloor(target-1) + JumpFloor(target-2);
        }
    }
}

代码示范2(优化了下):

public class Solution {
    
    
    public int JumpFloor(int target) {
    
    
        //关键:最后一次要么跳一级,要么跳2级
        int a = 0;
        int b = 0;
        int c = 1;
        for(int i = 1; i <=target; i++){
    
    
            a = b + c;
            b = c;
            c = a;
        }
        return a;
    }
}

斐波那契数列

时间限制:1秒 空间限制:32768K 热度指数:407703

题目描述
大家都知道斐波那契数列,现在要求输入一个整数n,请你输出斐波那契数列的第n项(从0开始,第0项为0)。
n<=39

方案一(递归):

public class Solution {
    
    
    public int Fibonacci(int n) {
    
    
        if(n == 0){
    
    
            return 0; 
        }else if(n == 1){
    
    
            return 1;
        }else{
    
    
            return Fibonacci(n-1) + Fibonacci(n-2);
        }
    }
}

方案二(递推/动态规划):

public class Solution {
    
    
    public int Fibonacci(int n) {
    
    
        int[] a = new int[40];
        a[0] = 0;
        a[1] = 1;
        for(int i = 2; i <=39; i++){
    
    
            a[i] = a[i-1] + a[i-2];
        }
        return a[n];
    }
}

旋转数组的最小数字

时间限制:3秒 空间限制:32768K 热度指数:429333
本题知识点: 查找

题目描述
把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。 输入一个非减排序的数组的一个旋转,输出旋转数组的最小元素。 例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。 NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。

import java.util.ArrayList;
public class Solution {
    
    
    public int minNumberInRotateArray(int [] array) {
    
    
        if(array.length == 0){
    
    
            return 0;
        }
        for(int i = 0; i < array.length-1; i++){
    
    
            if(array[i] > array[i+1]){
    
    
                return array[i+1];
            }
        }
        return array[0];
    }
}

用两个栈来实现一个队列

时间限制:1秒 空间限制:32768K 热度指数:312041
本题知识点: 队列 栈

题目描述
用两个栈来实现一个队列,完成队列的Push和Pop操作。 队列中的元素为int类型。

思路
stack1用来入队。出队的话,就把stack1依次出栈压入stack2中,再把stack2弹出一个(这个就是队头),然后再把stack2依次出栈压入stack1中,最后弹出队头。

import java.util.Stack;

public class Solution {
    
    
    Stack<Integer> stack1 = new Stack<Integer>();
    Stack<Integer> stack2 = new Stack<Integer>();
    
    public void push(int node) {
    
    
        stack1.push(node);
    }
    
    public int pop() {
    
    
        while(!stack1.empty()){
    
    
            stack2.push(stack1.pop());
        }
        int tmp = stack2.pop();
        while(!stack2.empty()){
    
    
            stack1.push(stack2.pop());
        }
        return tmp;
    }
}

重建二叉树

时间限制:1秒 空间限制:32768K 热度指数:468529

题目描述
输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。

思路
观察分析先序和中序序列,先序的第一个数必然是树根,根据这个树根从中序中找,树根左边是左子树,树根右边是右子树,树根左边的序列必然对应先序树根右边的序列,递归处理。

学习参考

/**
 * Definition for binary tree
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
public class Solution {
    
    
    public TreeNode reConstructBinaryTree(int [] pre,int [] in) {
    
    
        return reConstructBinaryTree(pre, 0, pre.length-1, in, 0, in.length-1);
    }
    
    private TreeNode reConstructBinaryTree(int[] pre, int preSt, int preEn, int[] in, int inSt, int inEn){
    
    
        if(preSt > preEn || inSt > inEn){
    
    
            return null;
        }
        TreeNode root = new TreeNode(pre[preSt]);
        for(int i = inSt; i <= inEn; i++){
    
    
            if(pre[preSt] == in[i]){
    
    
                root.left = reConstructBinaryTree(pre, preSt+1, preSt+i-inSt, in, inSt, i-1);
                root.right = reConstructBinaryTree(pre, preSt+i-inSt+1, preEn, in, i+1, inEn);
                break;
            }
        }
        return root;
    }
}

从未到头打印链表

题目描述
输入一个链表,按链表值从尾到头的顺序返回一个ArrayList。

思路1:先存储到一个ArrayList里面,然后转储到目标ArrayList里面

/**
*    public class ListNode {
*        int val;
*        ListNode next = null;
*
*        ListNode(int val) {
*            this.val = val;
*        }
*    }
*
*/
import java.util.ArrayList;
public class Solution {
    
    
    public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
    
    
        ArrayList<Integer> a = new ArrayList<Integer>();
        ArrayList<Integer> b = new ArrayList<Integer>();
        
        while(listNode != null){
    
    
            a.add(listNode.val);
            listNode = listNode.next;
        }
        for(int i = a.size() - 1; i >= 0; i--){
    
    
            b.add(a.get(i));
        }
        return b;
    }
}

思路2:借助栈

/**
*    public class ListNode {
*        int val;
*        ListNode next = null;
*
*        ListNode(int val) {
*            this.val = val;
*        }
*    }
*
*/
import java.util.ArrayList;
import java.util.Stack;
public class Solution {
    
    
    public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
    
    
        ArrayList<Integer> a = new ArrayList<Integer>();
        Stack<Integer> stack = new Stack<Integer>();
        
        while(listNode != null){
    
    
            stack.push(listNode.val);
            listNode = listNode.next;
        }
        while(!stack.empty()){
    
    
            a.add(stack.pop());
        }
        return a;
    }
}

替换空格

题目描述
请实现一个函数,将一个字符串中的每个空格替换成“%20”。例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy。

【关键点】
StringBuffer不能直接和字符串相加转成String,必须调用toString()才能转成String。。

思路1

public class Solution {
    
    
    public String replaceSpace(StringBuffer str) {
    
    
        String s = str.toString();
        StringBuffer out = new StringBuffer();
        for(int i = 0; i < s.length(); i++){
    
    
            char c = s.charAt(i);
            if(c == ' '){
    
    
                out.append("%20");
            }else{
    
    
                out.append(c);
            }
        }
        return out.toString();
    }
}

思路2:(比较烦的是不能直接插入String字符串,一个字符一个字符插)

public class Solution {
    
    
    public String replaceSpace(StringBuffer str) {
    
    
        for(int i = 0; i < str.length(); i++){
    
    
            if(str.charAt(i) == ' '){
    
    
                str.deleteCharAt(i);
                str.insert(i, '%');
                str.insert(i+1, '2');
                str.insert(i+2, '0');
            }
        }
        return str.toString();
    }
}

二维数组中的查找

题目描述
在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。

思路1:暴力

public class Solution {
    
    
    public boolean Find(int target, int [][] array) {
    
    
        for(int[] a : array){
    
    
            for(int b : a){
    
    
                if(b == target){
    
    
                    return true;
                }
            }
        }
        return false;
    }
}

思路2:二分(注意二分区间是左闭右开还是左闭右闭的,如果是左闭右闭,那么r=mid-1)

public class Solution {
    
    
    public boolean Find(int target, int [][] array) {
    
    
        for(int i = 0; i < array.length; i++){
    
    
            int l = 0;
            int r = array[i].length;//左闭右开
            while(l < r){
    
    
                int mid = (l+r)/2;
                if(array[i][mid] == target){
    
    
                    return true;
                }else if(array[i][mid] > target){
    
    
                    r = mid;//右边是开的,所以这里mid不能减去1
                }else{
    
    
                    l = mid + 1;
                }
            }
        }
        return false;
    }
}

参考资料

[1] https://www.nowcoder.com/ta/coding-interviews

猜你喜欢

转载自blog.csdn.net/ccnuacmhdu/article/details/105875470
今日推荐