LeetCode 中级算法 JAVA实现

面试题目15:三数之和

将数组排序,遍历数组,以当前数为第一个数,在后面的序列中寻找剩余的两个数(头尾指针方式)。注意当前数大于0则可结束,且需要跳过重复的数。
public static List<List<Integer>> threeSum(int[] nums) {
        List<List<Integer>> lists = new ArrayList<>();
        if (nums == null || nums.length<=2){
            return lists;
        }
        Arrays.sort(nums);
        for (int x = 0;x<=nums.length-3;x++){
            if (nums[x]>0){
                return lists;
            }
            if (x>0 && nums[x] == nums[x-1]){
                continue;
            }
            find(nums,x+1,nums.length-1,nums[x],lists);
        }
        return lists;
    }
    public static void find(int[] nums,int start,int end,int number,List<List<Integer>> lists){
        while (start<end){
            int temp =nums[start] + nums[end] + number;
            if (temp == 0){
                List<Integer> thistime = new ArrayList<>();
                thistime.add(nums[start]);
                thistime.add(nums[end]);
                thistime.add(number);
                lists.add(thistime);
                while (start<end && nums[start+1] == nums[start]){
                    start++;
                }
                start++;
                while (start<end && nums[end-1] == nums[end]){
                    end--;
                }
                end--;
            }else if (temp<0){
                start++;
            }else {
                end--;
            }
        }
    }

面试题73:矩阵置0

用第一行及第一列来记录出现0的行列,首先记录下第一行第一列是否有0。
    public static void setZeroes(int[][] matrix) {
        if (matrix == null || matrix.length == 0||matrix[0].length == 0){
            return;
        }
        int row = matrix.length;
        int col = matrix[0].length;

        for (int x = 0;x<=row-1;x++){
            for (int y = 0;y<=col-1;y++){
                if (matrix[x][y] == 0){
                    reset(matrix,x,y,row,col);
                }
            }
        }
        for (int x = 0;x<=row-1;x++){
            for (int y = 0;y<=col-1;y++){
                if (matrix[x][y] ==Integer.MIN_VALUE){
                    matrix[x][y] = 0;
                }
            }
        }

    }
    public static void reset(int[][] matrix,int x,int y,int row,int col){
        for (int i = 0;i<=col-1;i++){
            if (matrix[x][i]!=0){
                matrix[x][i] = Integer.MIN_VALUE;
            }
        }
        for (int i = 0;i<=row-1;i++){
            if (matrix[i][y]!=0){
                matrix[i][y] = Integer.MIN_VALUE;
            }
        }
    }

面试题49:字母异位词分组

遍历字符串数组,用hashmap辅助,每读一个就将其字符串排序,不存在则添加,存在则添加其下标,再遍历hashmap生成返回答案
    public static List<List<String>> groupAnagrams(String[] strs) {
        List<List<String>> lists = new ArrayList<>();
        if (strs == null){
            return lists;
        }
        HashMap<String,ArrayList<Integer>> hashMap = new HashMap<>();
        for (int x = 0;x<=strs.length-1;x++){
            char[] temp = strs[x].toCharArray();
            Arrays.sort(temp);
            String temp_st = String.valueOf(temp);
            if (hashMap.containsKey(temp_st)){
                hashMap.get(temp_st).add(x);
            }else {
                ArrayList<Integer> group = new ArrayList<>();
                group.add(x);
                hashMap.put(temp_st,group);
            }

        }
        for (ArrayList<Integer> temp :hashMap.values()){
            List<String> group = new ArrayList<>();
            for (int x: temp){
                group.add(strs[x]);
            }
            lists.add(group);
        }
        return lists;
    }

面试题3:无重复字符的最长子串

遍历字符串,不断更新子串及最大长度
public static int lengthOfLongestSubstring(String s) {
        if (s == null || s.length() == 0){
            return 0;
        }
        StringBuilder stringBuilder = new StringBuilder();
        int max = 0;
        int substring = 0;
        char[] s_char = s.toCharArray();
        for (int x = 0;x<=s_char.length-1;x++){
            if (stringBuilder.indexOf(String.valueOf(s_char[x])) == -1){
                stringBuilder.append(s_char[x]);
                substring++;
            }else {
                int lastindex = stringBuilder.lastIndexOf(String.valueOf(s_char[x]));
                stringBuilder.delete(0,lastindex+1);
                stringBuilder.append(s_char[x]);
                substring = stringBuilder.length();
            }
            if (max<substring){
                max = substring;
            }
        }
        return max;

    }

面试题5:最长回文子串

动态规划求解,p[i.j] = true  when p[i+1,j-1] = true && p[i] = p[j]
public static String longestPalindrome(String s) {
        if (s == null || s.length() == 0){
            return "";
        }

        int start = 0;
        int maxlenth = 0;
        boolean[][] palindrome = new boolean[s.length()][s.length()];
        char[] s_char = s.toCharArray();
        for (int x = 0;x<=s_char.length-1;x++){
            palindrome[x][x] = true;
            if (x<s_char.length-1 && s_char[x] == s_char[x+1]){
                palindrome[x][x+1] = true;
                start = x;
                maxlenth = 2;
            }
        }
        if (maxlenth == 0){
            maxlenth = 1;
            start = 0;
        }
        for (int x = 3;x<=s_char.length;x++){
            for (int y = 0;y<=s_char.length-x;y++){
                int end = y+x-1;
                if (palindrome[y+1][end-1] && s_char[y] == s_char[end]){
                    palindrome[y][end] = true;
                    maxlenth = x;
                    start = y;
                }
            }
        }
        if (maxlenth>0){
            return s.substring(start,start+maxlenth);
        }
        return "";
    }

面试题334:递增的三元子序列

用两个指针,当当前数小于第一个指针时,第一个指针变为当前数,当前数小于第二个指针时,第二个指针变为当前数,第一个指针维护最小值,第二个指针维护较小值,当前数大于第二个指针时,说明存在第三个数,输出true。
public static boolean increasingTriplet(int[] nums) {
        if (nums == null || nums.length <=2){
            return false;
        }
        int index1 = Integer.MAX_VALUE;
        int index2 = Integer.MAX_VALUE;
        for (int x = 0;x<=nums.length-1;x++){
            if (index1>nums[x]){
                index1 = nums[x];
            }else if (nums[x]>index1 && nums[x]<index2){
                index2 = nums[x];
            }else if (nums[x]>index2){
                return true;
            }
        }
        return false;

    }

面试题2:两数相加

按位相后走,注意进位问题
    public static ListNode addTwoNumbers(ListNode l1, ListNode l2) {
        if(l1 == null || l2 == null){
            return null;
        }
        ListNode head = new ListNode(-1);
        ListNode rem = head;
        int carry = 0;
        while (l1!=null && l2!=null){
            int temp = l1.val+l2.val+carry;
            if (temp > 9){
                carry = 1;
                temp = temp-10;
            }else {
                carry = 0;
            }
            ListNode tp = new ListNode(temp);
            rem.next = tp;
            rem = rem.next;
            l1 = l1.next;
            l2 = l2.next;
        }
        while (l1!=null){
            int temp = l1.val+carry;
            if (temp > 9){
                carry = 1;
                temp = temp-10;
            }else {
                carry = 0;
            }
            ListNode tp = new ListNode(temp);
            rem.next = tp;
            rem = rem.next;
            l1 = l1.next;
        }
        while (l2!=null){
            int temp = l2.val+carry;
            if (temp > 9){
                carry = 1;
                temp = temp-10;
            }else {
                carry = 0;
            }
            ListNode tp = new ListNode(temp);
            rem.next = tp;
            rem = rem.next;
            l2 = l2.next;
        }
        if (carry == 1){
            ListNode tp = new ListNode(1);
            rem.next = tp;
        }
        return head.next;
    }

面试题328:奇偶链表

用两个指针,一个指向奇数,一个指向偶数,把偶数后出现的奇数移到目前的奇数后面,再将两个指针分别移动一位,此时偶数指针再次指向偶数位置。
public static ListNode oddEvenList(ListNode head) {
        if (head == null || head.next == null){
            return head;
        }
        ListNode odd = head;
        ListNode even = head.next;
        while (even!= null && even.next!=null){
            ListNode temp = even.next;
            even.next = even.next.next;
            temp.next = odd.next;
            odd.next = temp;
            odd = odd.next;
            even = even.next;
        }
        return head;
    }

面试题160:相交链表

计算两个的长度,调整为相同,再顺序遍历
分别遍历,当某链表读完后跳到另外一条的头继续开始读,最后会在交点相遇或在结尾(null)相遇
public static ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        if (headA == null || headB == null){
            return null;
        }
        int lenthA = getlenth(headA);
        int lenthB = getlenth(headB);

        int dif = lenthA > lenthB ? lenthA-lenthB:lenthB-lenthA;
        ListNode first = headA;
        ListNode second = headB;
        if (lenthA > lenthB){
            for (int x = 1;x<=dif;x++){
                first = first.next;
            }
        }else {
            for (int x = 1;x<=dif;x++){
                second = second.next;
            }
        }

        while (first!=null){
            if (first.val == second.val){
                return first;
            }
            first = first.next;
            second = second.next;
        }
        return null;


    }
    public static int getlenth(ListNode temp){
        int lenth = 0;
        while (temp!=null){
            lenth++;
            temp = temp.next;
        }
        return lenth;
    }

面试题94:二叉树的中序遍历(不用递归)

用栈来辅助,左节点入栈,出栈时访问节点,若有右节点,再入栈,继续找其左节点,按左中右访问
用两个指针,需要把空右节点指向中序遍历中的下一位。
public static List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> reback = new ArrayList<>();
        if (root == null){
            return reback;
        }
        Stack<TreeNode> stack = new Stack<>();
        TreeNode temp = root;
        while (temp!=null || stack.size()!=0){
            while (temp!=null){
                stack.push(temp);
                temp = temp.left;
            }
            TreeNode now = stack.pop();
            reback.add(now.val);
            temp = now.right;
        }

        return reback;
    }

面试题103:二叉树的锯齿形层次遍历

用两个队列,第一个队列存这一层的,另一个队列存下一层的,注意加入左右节点的顺序
public static List<List<Integer>> zigzagLevelOrder(TreeNode root) {
        List<List<Integer>> lists = new ArrayList<>();
        if (root == null){
            return lists;
        }
        ArrayDeque<TreeNode> arrayDeque = new ArrayDeque<>();
        arrayDeque.addLast(root);
        ArrayDeque<TreeNode> temp = new ArrayDeque<>();

        int flag = 0;

        List<Integer> layer = new ArrayList<>();
        while (arrayDeque.size()!=0){
            TreeNode now = arrayDeque.pollLast();
            layer.add(now.val);
            if (flag == 0){
                if (now.left!=null){
                    temp.addLast(now.left);
                }
                if (now.right!=null){
                    temp.addLast(now.right);
                }
            }else {
                if (now.right!=null){
                    temp.addLast(now.right);
                }
                if (now.left!=null){
                    temp.addLast(now.left);
                }
            }
            if (arrayDeque.size()==0){
                ArrayDeque<TreeNode> exchange = temp;
                temp = arrayDeque;
                arrayDeque = exchange;

                flag = 1-flag;
                lists.add(layer);
                layer = new ArrayList<>();
            }

        }
        return lists;
    }

面试题105:从前序和中序遍历构建树(剑指offer写过)

递归,指针可优化,这里我写的用了hashmap
    public static TreeNode buildTree(int[] preorder, int[] inorder) {
        if (preorder == null || inorder == null || preorder.length!=inorder.length ||preorder.length == 0){
            return null;
        }
        HashMap<Integer,Integer> hashMap = new HashMap<>();
        for (int x = 0;x<=preorder.length-1;x++){
            hashMap.put(preorder[x],x);
        }
        TreeNode root =buildtree_core(hashMap,inorder,0,inorder.length-1);
        return root;
    }
    public static TreeNode buildtree_core(HashMap<Integer,Integer> preorder,int[] inorder,int start,int end){
        if (start > end){
            return null;
        }
        int index = firstone(preorder,inorder,start,end);
//        System.out.print(index);
        TreeNode root = new TreeNode(inorder[index]);
        TreeNode left = buildtree_core(preorder,inorder,start,index-1);
        TreeNode right = buildtree_core(preorder,inorder,index+1,end);
        root.left = left;
        root.right = right;
        return root;
    }
    public static int firstone(HashMap<Integer,Integer> preorder,int[] inorder,int start,int end){
        int min = inorder.length;
        int reback = start;
        for (int x = start;x<=end;x++){
            int index = preorder.get(inorder[x]);
            if (index<min){
                min = index;
                reback = x;
            }
        }
        return reback;
    }

面试题116:填充同一层的兄弟节点

子树之间的节点连接可以借助上层父节点之间的next指针
    public static void connect(TreeLinkNode root) {
        if (root == null){
            return;
        }
        root.next = null;
        if (root.left!=null){
            root.left.next = root.right;
            root.right.next = null;
        }
        connect_core(root.left);
        connect_core(root.right);

    }
    public static void  connect_core(TreeLinkNode root){
        if (root== null || root.left == null){
            return;
        }
        root.left.next = root.right;
        if (root.next!=null){
            root.right.next = root.next.left;
        }else {
            root.right.next = null;
        }
        connect_core(root.left);
        connect_core(root.right);
    }

面试题230:二叉搜索树中第k小的元素

二叉搜索树的中序遍历是有序的,也可以通过子树节点个数来判断
public static int kthSmallest(TreeNode root, int k) {
        if (root == null || k<=0){
            return -1;
        }
        ArrayList<Integer> nums = new ArrayList<>();
        getNums(root,nums);
        return nums.get(k-1);
    }
    public static void getNums(TreeNode root,ArrayList<Integer> array){
        if (root == null){
            return;
        }
        getNums(root.left,array);
        array.add(root.val);
        getNums(root.right,array);
    }

面试题200:岛屿的个数

遍历数组,每遇到一个1,就将岛屿数+1,将该1置位0,且将周围的1都置为0,再去找下一个1;
public static int numIslands(char[][] grid) {
        int lands = 0;
        if (grid == null || grid.length == 0 || grid[0].length == 0){
            return lands;
        }
        for (int x = 0;x<=grid.length-1;x++){
            for (int y = 0;y<=grid[0].length-1;y++){
                if (grid[x][y] == '1'){
                    numIsland_core(grid,x,y);
                    lands++;
                }
            }
        }
        return lands;
    }
    public static void numIsland_core(char[][] grid,int x ,int y){
        grid[x][y] = '0';
        if (x>0 && grid[x-1][y] == '1'){
            numIsland_core(grid,x-1,y);
        }
        if (y>0 && grid[x][y-1] == '1'){
            numIsland_core(grid,x,y-1);
        }
        if (x<grid.length-1 && grid[x+1][y] == '1'){
            numIsland_core(grid,x+1,y);
        }
        if (y<grid[0].length-1 && grid[x][y+1] == '1'){
            numIsland_core(grid,x,y+1);
        }
    }

面试题17:电话号码的字母组合

递归,需要传递给下一次,下次需要填的位置,已有的字符串。
    public static List<String> letterCombinations(String digits) {
        List<String> reback = new ArrayList<>();
        if (digits == null || digits.length() == 0){
            return reback;
        }
        String[] nums = {"abc","def","ghi","jkl","mno","pqrs","tuv","wxyz"};
        letter_core(digits,nums,0,"",reback);
        return reback;
    }
    public static void letter_core(String digits,String[] nums,int start,String res,List<String> reback){
        if (start == digits.length()){
            reback.add(res);
            return;
        }
        String str = nums[digits.charAt(start)-'0'-2];
        for (int x = 0;x<=str.length()-1;x++){
            String temp = res+str.charAt(x);
            letter_core(digits,nums,start+1,temp,reback);
        }

    }

面试题22:括号生成

递归,用左右括号的数量进行控制,若左括号数量小于右括号会出现错误情况,当剩余括号数为0,则添加字符串,注意不要改动当层的string,在传入参数时直接改动
    public static List<String> generateParenthesis(int n) {
        List<String> reback = new ArrayList<>();
        if (n<=0){
            return reback;
        }
        int left = n;
        int right = n;
        core(n,n,reback,"");
        return reback;
    }
    public static void core(int left,int right,List<String> reback,String string){
        if (left>right){
            return;
        }else if (left == 0 && right == 0){
            reback.add(string);
            return;
        }

        if (left>0){
            core(left-1,right,reback,string+'(');
        }
        if (right>0){
            core(left,right-1,reback,string+')');
        }
    }

面试题46:全排列

递归问题,每次循环时需要检查当前数是否已出现过
public static List<List<Integer>> permute(int[] nums) {
        List<List<Integer>> lists = new ArrayList<>();
        if (nums == null || nums.length == 0){
            return lists;
        }
        core(nums,0,lists,"");
        return lists;
    }
    public static void core(int[] nums,int start,List<List<Integer>> lists,String temp){
        if (start == nums.length){
            List<Integer> list = new ArrayList<>();
            String[] strings = temp.split(",");
            for (String s :strings){
                if (s.length()!=0){
                    list.add(Integer.valueOf(s));
                }
            }
            lists.add(list);
            return;
        }
        for (int x = 0;x<=nums.length-1;x++){
            boolean cando = true;
            String[] strings = temp.split(",");
            for (String s :strings){
                if (s.equals( String.valueOf(nums[x]))){
                    cando = false;
                }
            }
            if (cando) {
                core(nums, start + 1, lists, temp + String.valueOf(nums[x]) + ',');
            }
        }
    }

面试题78:子集

可以用递归的方法,不断地从剩余的数中选择数。需要传递还需选择的个数,开始角标,已选择的数,在插入时需要判断是否已有此集合
public static List<List<Integer>> subsets(int[] nums) {
        List<List<Integer>> lists = new ArrayList<>();
        if (nums == null || nums.length == 0){
            return lists;
        }
        int lenth = nums.length;
        for (int x = 0;x<=lenth;x++){
            core(nums,x,0,lists,"");
        }
        return lists;
    }
    public static void core(int[] nums,int needchoose,int start,List lists,String temp){
        String[] strings = temp.split(":");
        List<Integer> st = new ArrayList<>();
        for (String x:strings){
            if (x.length()!=0){
                st.add(Integer.valueOf(x));
            }
        }
        if (needchoose == 0){
            Collections.sort(st);
            if (!lists.contains(st)){
                lists.add(st);
            }
            return;
        }
        for (int x = start;x<=nums.length-1;x++){

            if (!st.contains(nums[x])){
                core(nums,needchoose-1,start+1,lists,temp+String.valueOf(nums[x])+':');
            }
        }
    }

面试题79:单词搜索

递归,向上下左右,需要传递当前坐标,匹配到的位数,访问下一位时,此位需要替换成其他符号,避免重复访问
public static boolean exist(char[][] board, String word) {
        if (board == null || word == null || board.length == 0 || board[0].length == 0 || word.length() == 0){
            return false;
        }
        int row = board.length;
        int col = board[0].length;
        boolean reback = false;
        for (int x = 0;x<=row-1;x++){
            for (int y = 0;y<=col-1;y++){
                reback = core(board,row,col,x,y,word,0);
                if (reback){
                    return reback;
                }
            }
        }
        return reback;
    }
    public static boolean core(char[][] board,int row,int col,int nowrow,int nowcol,String word,int index){
        if (index == word.length()){
            return true;
        }
        if (nowrow>=row || nowcol>=col || nowrow<0 || nowcol<0){
            return false;
        }
        boolean reback = false;
        if (board[nowrow][nowcol] == word.charAt(index)){
            char temp = board[nowrow][nowcol];
            board[nowrow][nowcol] = '*';
            reback =
                    (core(board,row,col,nowrow-1,nowcol,word,index+1) ||
                            core(board,row,col,nowrow+1,nowcol,word,index+1) ||
                            core(board,row,col,nowrow,nowcol-1,word,index+1) ||
                            core(board,row,col,nowrow,nowcol+1,word,index+1));
            if (!reback){
                board[nowrow][nowcol] = temp;
            }
        }

        return reback;

    }

面试题75:分类颜色

start指针维护0的位置,end指针维护2的位置,遍历数组,若扫描到0,与start交换,并start++,若扫描到1,则继续,若扫描到2,则与end交换,end--,此时交换回来的数可能是0,1,2,x指针也需回退一格。
public static void sortColors(int[] nums) {
        if (nums == null || nums.length <=1){
            return;
        }
        int start  = 0;
        int end = nums.length-1;
        for (int x = 0;x<=end;x++){
            if (nums[x] == 0){
                swap(nums,start,x);
                start++;
            }else if(nums[x] == 2){
                swap(nums,end,x);
                x--;
                end--;
            }
        }
    }
    public static void swap(int[] nums,int index1,int index2){
        int temp = nums[index1];
        nums[index1] = nums[index2];
        nums[index2] = temp;
    }

面试题347:前k个高频元素

先用hashmap存下数量,再用堆排序进行排序(priorityqueue)
    public static List<Integer> topKFrequent(int[] nums, int k) {
        List<Integer> list = new ArrayList<>();
        if (nums == null || nums.length == 0 || k<=0 || k>nums.length){
            return list;
        }
        HashMap<Integer,Integer> hashMap = new HashMap<>();
        for (int x : nums){
            if (hashMap.containsKey(x)){
                hashMap.put(x,hashMap.get(x)+1);
            }else {
                hashMap.put(x,1);
            }
        }
        if (k>hashMap.size()){
            return list;
        }
        PriorityQueue<Map.Entry<Integer,Integer>> priorityQueue = new PriorityQueue<>(new Comparator<Map.Entry<Integer,Integer>>() {
            @Override
            public int compare(Map.Entry<Integer,Integer> o1, Map.Entry<Integer,Integer> o2) {
                if (o1.getValue()>o2.getValue()){
                    return -1;
                }else if (o1.getValue()<o2.getValue()){
                    return 1;
                }else {
                    return 0;
                }
            }
        });
        for (Map.Entry<Integer,Integer> x:hashMap.entrySet()){
            priorityQueue.add(x);
        }
        for (int x = 0; x<=k-1;x++){
            Map.Entry<Integer,Integer> temp = priorityQueue.poll();
            list.add(temp.getKey());
            priorityQueue.remove(temp);
        }
        return list;
    }

面试题215:数组的第k个最大元素

排序,然后找
利用快排的算法,若排了之后刚好在第k-1位则找到,若大于,则说明在其左边,小于在其右边
public static int findKthLargest(int[] nums, int k) {
        if (nums == null || nums.length == 0 || k <=0 || k>nums.length){
            return -1;
        }
        TreeMap<Integer,Integer> treeMap = new TreeMap<>();
        for (int x : nums){
            if (treeMap.containsKey(x)){
                treeMap.put(x,treeMap.get(x)+1);
            }else {
                treeMap.put(x,1);
            }
        }
        while (k>0){
            Map.Entry<Integer,Integer> temp = treeMap.lastEntry();
            int next = k-temp.getValue();
            if (next <= 0){
                return temp.getKey();
            }else{
                treeMap.remove(temp.getKey());
                k = next;
            }
        }
        return -1;
    }

面试题162:寻找峰值

二分查找,峰值一定存在
public static int findPeakElement(int[] nums) {
        if (nums == null || nums.length == 0){
            return -1;
        }
        int start = 0;
        int end = nums.length-1;
        while (start<=end){
            int mid = (end+start)/2;

            boolean peak = false;
            if (mid == 0){
                if (mid != nums.length-1){
                    peak = check(nums,mid,mid+1);
                    if (peak){
                        return mid;
                    }
                    start = mid+1;
                }else {
                    return mid;
                }
            }else {
                if (mid == nums.length-1){
                    peak = check(nums,mid,mid-1);
                    if (peak){
                        return mid;
                    }
                    end = mid-1;
                }else {
                    peak = check(nums,mid,mid-1) && check(nums,mid,mid+1);
                    if (peak){
                        return mid;
                    }
                    if (nums[mid-1]>nums[mid]){
                        end = mid-1;
                    }else if (nums[mid+1]>nums[mid]){
                        start = mid+1;
                    }
                }
            }

        }
        return -1;
    }
    public static boolean check(int[] nums ,int index1,int index2){

        if (nums[index1] > nums[index2]){
            return true;
        }else {
            return false;
        }
    }

面试题34:搜索范围

二分查找,然后向周边找范围
public static int[] searchRange(int[] nums, int target) {
        int[] reback = {-1,-1};

        if (nums == null || nums.length == 0){
            return reback;
        }

        int pre = 0;
        int after = nums.length-1;
        while (pre <= after){
            int mid = (pre+after)/2;
            if (nums[mid] == target){
                int start = mid;
                int end = mid;
                while (start>=0){
                    if (nums[start] == nums[mid]){
                        if (start == 0){
                            reback[0] = 0;
                            break;
                        }
                        start--;
                    }else {
                        reback[0] = start+1;
                        break;
                    }
                }
                while (end<=nums.length-1){
                    if (nums[end] == nums[mid]){
                        if (end == nums.length-1){
                            reback[1] = nums.length-1;
                            break;
                        }
                        end++;
                    }else {
                        reback[1] = end-1;
                        break;
                    }
                }
                return reback;
            }else if (nums[mid]<target){
                pre = mid+1;
            }else {
                after = mid-1;
            }
        }
        return reback;
    }

面试题56:合并区间

先需要将区间排序,然后遍历,如果出现重叠,再进行合并;
    public static List<Interval> merge(List<Interval> intervals) {
        List<Interval> list = new ArrayList<>();
        if (intervals == null || intervals.size() == 0){
            return list;
        }else if (intervals.size() == 1){
            return intervals;
        }
        PriorityQueue<Interval> priorityQueue = new PriorityQueue<>(new Comparator<Interval>() {
            @Override
            public int compare(Interval o1, Interval o2) {
                if (o1.start > o2.start){
                    return -1;
                }else if (o1.start < o2.start){
                    return 1;
                }else {
                    return 0;
                }
            }
        });
        for (Interval x :intervals){
            priorityQueue.add(x);
        }
        Interval first = priorityQueue.poll();
        int start = first.start;
        int end = first.end;
        for (int x = 1;x<=intervals.size()-1;x++){
            Interval temp = priorityQueue.poll();
            if (temp.start<=end && temp.end >= start){
                start = start<temp.start?start:temp.start;
                end = end>temp.end?end:temp.end;
            } else {
                Interval another = new Interval(start,end);
                list.add(another);
                start = temp.start;
                end = temp.end;
            }
            if (x == intervals.size()-1){
                Interval another = new Interval(start,end);
                list.add(another);
            }
        }
        return list;

    }

面试题33:搜索旋转排序数组

数组变成了两段递增的数组,可以通过mid与0的值判断其是左边有序还是右边有序,进而进行判断选择在哪边进行下一次选择


public static int search(int[] nums, int target) {
        if (nums == null || nums.length == 0){
            return -1;
        }
        int start = 0;
        int end = nums.length-1;
        while (start <= end){
            int mid = (start+end)/2;

            if (nums[mid] == target){
                return mid;
            }
            if (nums[mid] >= nums[0]){
                if (nums[0] <= target && nums[mid] > target){
                    end = mid-1;
                }else {
                    start = mid+1;
                }
            }else {
                if (nums[mid] <target && nums[nums.length-1] >=target){
                    start = mid+1;
                }else {
                    end = mid-1;
                }
            }
        }
        return -1;
    }

面试题240:搜索二维矩阵

左上角或右下角的可以作为二分的分点
public static boolean searchMatrix(int[][] matrix, int target) {
        if (matrix == null || matrix.length == 0 || matrix[0].length == 0){
            return false;
        }
        int row = matrix.length;
        int col = matrix[0].length;
        int startcol = 0;
        int startrow = 0;
        for (int x = 0;x<=col-1;x++){
            if (matrix[row-1][x] == target){
                return true;
            }else if (matrix[row-1][x] > target){
                break;
            }else {
                startcol++;
            }
        }
        for (int x = 0;x<=row-1;x++){
            if (matrix[x][col-1] == target){
                return true;
            }else if (matrix[x][col-1] > target){
                break;
            }else {
                startrow++;
            }
        }
        for (int x = startrow;x<=row-1;x++){
            for (int y = startcol;y<=col-1;y++){
                if (matrix[x][y] == target){
                    return true;
                }else if (matrix[x][y] > target){
                    break;
                }
            }
        }
        return false;
    }

面试题55:跳跃游戏

贪心算法和动态规划都可以解,贪心算法即求最远可到的距离,遍历并更新即可
public static boolean canJump(int[] nums) {
        if (nums == null || nums.length == 0){
            return false;
        }
        boolean[] cango = new boolean[nums.length];
        cango[0] = true;
        for (int x = 0; x<=nums.length-2;x++){
            if (cango[x]){
                for (int y = x+1;y<=x+nums[x];y++){
                    if (y<=nums.length-1){
                        cango[y] = true;
                    }
                }
            }else{
                break;
            }
        }
        return cango[nums.length-1];

    }

面试题62:不同路径

动态规划,此格存在的解法 = 上面的格子+左边的格子
组合数学问题
public static int uniquePaths(int m, int n) {
        if (m<=0 || n<=0){
            return 0;
        }
        BigInteger index1 = jiecheng(m+n-2);
        BigInteger index2 = jiecheng(m-1);
        BigInteger index3 = jiecheng(n-1);
        return index1.divide(index2.multiply(index3)).intValue();
    }
    public static BigInteger jiecheng(int all){

        BigInteger start = new BigInteger("1");
        for (int x = 1;x<=all;x++){
            start = start.multiply(new BigInteger(String.valueOf(x)));
        }
        return start;
    }

面试题322:零钱兑换

动态规划:d(i) = min{d(i) , d(i- j)+1} 
public static int coinChange(int[] coins, int amount) {
        if (coins == null || coins.length == 0){
            return -1;
        }
        if (amount == 0){
            return 0;
        }
        int[] nums = new int[amount+1];
        int min = coins[0];
        for (int x :coins){
            if (x>amount){
                continue;
            }
            nums[x] = 1;
            if (min>x){
                min = x;
            }
        }
        if (min>amount){
            return -1;
        }
        for (int x = min+1;x<=amount;x++){
            if (nums[x] == 0) {
                int sum = Integer.MAX_VALUE;
                for (int y : coins) {
                    if (x - y >= min && x - y <= amount && nums[x - y] != 0 && nums[x - y] < sum) {
                        sum = nums[x - y] + 1;
                    }
                }
                if (sum == Integer.MAX_VALUE){
                    nums[x] = 0;
                }else {
                    nums[x] = sum;
                }
            }
        }
        if (nums[amount] == 0){
            return -1;
        }else {
            return nums[amount];
        }

    }

面试题300:最长上升子序列

动态规划o(n[2]) , 到i位置的最长子序列为d(i) =  maxd(j)+1 当i>j时;
维护一个数组。不是插入,而是替换
public static int lengthOfLIS(int[] nums) {
        if (nums == null || nums.length == 0){
            return 0;
        }
        ArrayList<Integer> arrayList = new ArrayList<>();
        arrayList.add(nums[0]);
        for (int x  = 0;x<=nums.length-1;x++){
            if (nums[x]>arrayList.get(arrayList.size()-1)){
                arrayList.add(nums[x]);
            }else if (nums[x] <= arrayList.get(0)){
                arrayList.set(0,nums[x]);
            }else {
                int index = 0;
                while (arrayList.get(index) < nums[x]){
                    index++;
                }
                arrayList.set(index,nums[x]);
            }
        }
        return arrayList.size();
    }

面试题297:二叉树的序列化与反序列化

按层次序列化,如果当前为null就不存其子节点了。反序列化时也需要用队列。直接用数组下标的话会因太大而过不了。
 public static String serialize(TreeNode root) {
        if (root == null){
            return "";
        }
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append(root.val);
        stringBuilder.append(",");
        ArrayDeque<TreeNode> arrayDeque = new ArrayDeque<>();
        arrayDeque.addLast(root);
        while (arrayDeque.size()!=0){
            TreeNode temp = arrayDeque.pollFirst();
            if (temp.left!=null){
                stringBuilder.append(temp.left.val);
                stringBuilder.append(",");
                arrayDeque.addLast(temp.left);
            }else {
                stringBuilder.append("#,");
            }
            if (temp.right!=null){
                stringBuilder.append(temp.right.val);
                stringBuilder.append(",");
                arrayDeque.addLast(temp.right);
            }else {
                stringBuilder.append("#,");
            }
        }
        return stringBuilder.substring(0,stringBuilder.length()-1).toString();
    }
    public static TreeNode deserialize(String data) {
        if (data == null || data.length() == 0){
            return null;
        }
        String[] nums = data.split(",");
        ArrayDeque<TreeNode> arrayDeque = new ArrayDeque<>();

        TreeNode root = null;
        boolean isleft = true;
        for (String x :nums){
            TreeNode current = null;
            if (!x.equals("#")){
                current = new TreeNode(Integer.valueOf(x));
            }
            if (root == null){
                root = current;
                arrayDeque.addLast(root);
                continue;
            }
            TreeNode temp = arrayDeque.peekFirst();
            if (isleft){
                temp.left = current;
                if (current!=null){
                    arrayDeque.addLast(current);
                }
                isleft = false;

            }else {
                temp.right = current;
                if (current!=null){
                    arrayDeque.addLast(current);
                }
                isleft =true;
                arrayDeque.poll();
            }

        }
        return root;
    }

面试题380:常数时间插入,删除,获取随机元素

常数时间插入和删除可以用Hash表做到,但获取随机元素则不行,故需要用两个数组结构组合,一个hashmap,存元素及其下标,一个arraylist存元素;
class RandomizedSet {
    ArrayList<Integer> arrayList = new ArrayList<>();
    HashMap<Integer,Integer> hashMap = new HashMap<>();
    /** Initialize your data structure here. */
    public RandomizedSet() {

    }

    /** Inserts a value to the set. Returns true if the set did not already contain the specified element. */
    public boolean insert(int val) {
        if (hashMap.containsKey(val)){
            return false;
        }else {
            arrayList.add(val);
            hashMap.put(val,arrayList.size()-1);
            return true;
        }
    }

    /** Removes a value from the set. Returns true if the set contained the specified element. */
    public boolean remove(int val) {
        if (!hashMap.containsKey(val)){
            return false;
        }else {
            int index = hashMap.get(val);
            int temp = arrayList.get(arrayList.size()-1);
            arrayList.set(index,temp);
            arrayList.remove(arrayList.size()-1);
            hashMap.put(temp,index);
            hashMap.remove(val);
            return true;
        }
    }

    /** Get a random element from the set. */
    public int getRandom() {
        if (arrayList.size()-1 >= 0){
            Random it = new Random();
            int index = it.nextInt(arrayList.size());
            return arrayList.get(index);
        }else {
            return -1;
        }
    }
}

面试题202:快乐数

直接无脑加会导致超时,算的时候应该把算过数保留在set里,如果是非快乐数,会出现循环,可以减少很多判断时间
    public static boolean isHappy(int n) {
        if (n<=0){
            return false;
        }
        HashSet<Integer> hashSet = new HashSet<>();
        int sum = nextNum(n);
        while (sum!=-1){
            if (sum == 1){
                return true;
            }else {
                if (hashSet.contains(sum)){
                    return false;
                }else {
                    hashSet.add(sum);
                }
                sum = nextNum(sum);
            }
        }
        return false;
    }
    public static int nextNum(int n){
        int sum = 0;
        String s = String.valueOf(n);
        for (int x = s.length()-1;x>=0;x--){
            int temp = s.charAt(x)-'0';
            sum += Math.pow(temp,2);
            if (sum>= Integer.MAX_VALUE){
                return -1;
            }
        }
        return sum;
    }

面试题172:阶乘后的0

尾数为0为2*5产生,而产生5时肯定已产生多于5的2,故转化为求5的个数,可以用递归求解,也可以分别求出5,25,...的倍数相加
public static int trailingZeroes(int n) {
        if (n<=0){
            return 0;
        }
        int numof5 = 0;
        int max = (int)Math.floor(Math.log(n)/Math.log(5));
        for (int x = 1;x<=max;x++){
            int num = (int)Math.pow(5,x);
            numof5 += n/num;
        }
        return numof5;

    }

 面试题171:excel表序列号

26进制转换为10进制
public static int titleToNumber(String s) {
        if (s == null || s.length() == 0){
            return 0;
        }
        HashMap<Character,Integer> hashMap = new HashMap<>();
        char startchar = 'A';
        for (int x = 1;x<=26;x++){
            hashMap.put(startchar,x);
            startchar = (char)(startchar+1);
        }
        int sum = 0;
        for (int x = 0;x<=s.length()-1;x++){
            int temp = hashMap.get(s.charAt(x));
            int sum_temp = (int)(temp*Math.pow(26,s.length()-1-x));
            sum += sum_temp;
        }
        return sum;
    }

面试题50:Pow(x,n)

o(n)的算法:按个数乘,递归会stackoverflow
o(logn):二分算法
常数复杂度:按n中1的个数计算
需要特别注意 n为INT_MIN时,-n不是对应的,因为越界了,只能取到INT_MAX,此时还需要乘x;以及x=0时,x为double,判断不能用 ==;
double half = myPow(x,n/2);
        if (n%2 == 0){
            return half*half;
        }else {
            return half*half*x;
        }    public static double myPow(double x, int n) {
        if ( n == 0){
            return 1;
        }
        if (x < 0.000000001 && x> -0.000000001){
            return 0;
        }
        if (n<0){
            if (n == Integer.MIN_VALUE){
                return 1.0/(myPow(x,Integer.MAX_VALUE))*x;
            }
            return 1.0/myPow(x,-n);
        }
        double half = myPow(x,n/2);
        if (n%2 == 0){
            return half*half;
        }else {
            return half*half*x;
        }
    }

面试题69:x的平方根

相当于在有序的序列中寻找一个数,故可以用二分进行,要注意数超出整数范围的问题
public static int mySqrt(int x) {
        if (x<0){
            return -1;
        }else if (x==0){
            return 0;
        }
        int start = 1;
        int end = x;
        BigInteger num = new BigInteger(String.valueOf(x));
        while (start<=end){
            int mid = start+(end-start)/2;
            BigInteger temp = new BigInteger(String.valueOf(mid));
            int index = temp.multiply(temp).compareTo(num);
            if (index == 0){
                return mid;
            }else if (index == -1){
                start = mid+1;
            }else {
                end = mid-1;
            }
        }
        return end;
    }

面试题29:两数相除

用移位运算,尽量每次减去较大的一块,注意当被除数为-MIN,除数为-1时需要返回MAX,为了防止越界,中间计算用long包装一下
public static int divide(int dividend, int divisor) {
        if (divisor == 0){
            return -1;
        }
        if (dividend == Integer.MIN_VALUE && divisor == -1){
            return Integer.MAX_VALUE;
        }
        long dend = Math.abs((long)dividend);
        long dsor = Math.abs((long)divisor);
        int fuhao = -1;
        if ((dividend >0 && divisor >0) || (dividend<0 && divisor<0)){
            fuhao = 1;
        }
        if (dsor == 1){
            return (int)(fuhao*dend);
        }
        int res = 0;
        while (dend>=dsor){
            long temp = dsor;
            long p = 1;
            while (dend >= (temp<<1)){
                temp <<= 1;
                p <<= 1;
            }
            res += p;
            dend -= temp;
        }
        return fuhao*res;

    }

面试题166:分数到小数

直接除出来然后在商里找规律不太容易,采取的是记录下每次的余数,然后比较余数是否出现过,需要注意特殊值0,越界(用long包装)
    public static String fractionToDecimal(int numerator, int denominator) {
        if (denominator == 0){
            return "";
        }else if (numerator == 0){
            return "0";
        }
        long num = Math.abs((long)numerator);
        long deno = Math.abs((long)denominator);
        boolean isneg = (numerator > 0 && denominator < 0) || (numerator<0 && denominator>0);
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append((isneg?"-":"")+num/deno);
        long rem = num%deno;
        if (rem == 0){
            return stringBuilder.toString();
        }else {
            stringBuilder.append('.');
        }
        HashMap<Long,Integer> hashMap = new HashMap<>();
        int pos = stringBuilder.indexOf(".")+1;
        hashMap.put(rem, pos);
        while (rem!=0){
            rem = rem*10;
            stringBuilder.append(rem/deno);
            rem = rem%deno;
            if (hashMap.containsKey(rem)){
                int index = hashMap.get(rem);
                stringBuilder.insert(index,'(');
                stringBuilder.append(')');
                return stringBuilder.toString();
            }
            pos++;
            hashMap.put(rem,pos);

        }
        return stringBuilder.toString();
    }

面试题371:两整数之和

用异或算不带进位的和,然后用与操作与移位操作算进位。
public static int getSum(int a, int b) {
        while (a!=0){
            int temp = (a&b)<<1;
            b = a^b;
            a = temp;
        }
        return b;
    }

面试题150:逆波兰表达式求值

用栈存数字,当遇到操作符,取出两个数,再把计算结果入栈
public static int evalRPN(String[] tokens) {
        if (tokens == null || tokens.length == 0){
            return -1;
        }
        Stack<Integer> stack = new Stack<>();
        for (String x :tokens){
            if (x.equals("+") || x.equals("-") || x.equals("*") || x.equals("/")){
                int num1 = stack.pop();
                int num2 = stack.pop();
                if (x.equals("+")){
                    stack.push(num1+num2);
                }else if (x.equals("-")){
                    stack.push(num2-num1);
                }else if (x.equals("*")){
                    stack.push(num1*num2);
                }else {
                    stack.push(num2/num1);
                }
            }else {
                stack.push(Integer.valueOf(x));
            }
        }
        return stack.pop();
    }

面试题169:求众数

可以用hashmap求解,也可以假设第一个数为众数,然后设定计数器,相同+1,不同-1,若计数器为0,更换当前数为众数
    public static int majorityElement(int[] nums) {
        if (nums == null || nums.length == 0){
            return -1;
        }
        HashMap<Integer,Integer> hashMap = new HashMap<>();
        for (int x:nums){
            if (hashMap.containsKey(x)){
                hashMap.put(x,hashMap.get(x)+1);
            }else {
                hashMap.put(x,1);
            }
            if (hashMap.get(x) > Math.floor(nums.length/2)){
                return x;
            }
        }
        return -1;
    }

面试题621:任务调度器

将任务按个数排序,然后建立大小为n+1的数组,每次从队列中取数,若队列不足,则加上此轮放入数组的次数;否则加上整个数组大小;再遍历数组,将每个任务-1,再放入队列;
public static int leastInterval(char[] tasks, int n) {
        if (tasks == null || tasks.length == 0 || n<0){
            return 0;
        }
        int res = 0;
        int cycle = n+1;
        HashMap<Character,Integer> hashMap = new HashMap<>();
        for (char x:tasks){
            if (hashMap.containsKey(x)){
                hashMap.put(x,hashMap.get(x)+1);
            }else {
                hashMap.put(x,1);
            }
        }
        PriorityQueue<Integer> priorityQueue = new PriorityQueue<>(new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                if (o1>o2){
                    return -1;
                }else if (o1<o2){
                    return 1;
                }else {
                    return 0;
                }
            }
        });
        for (Map.Entry<Character,Integer> x:hashMap.entrySet()){
            priorityQueue.add(x.getValue());
        }
        System.out.print(priorityQueue.toString());
        while (priorityQueue.size()!=0){
            int cnt = 0;
            ArrayList<Integer> arrayList = new ArrayList<>();
            for (int i = 0;i<cycle;i++){
                if (priorityQueue.size()!=0){
                    arrayList.add(priorityQueue.peek());
                    priorityQueue.poll();
                    cnt++;
                }
            }
            for (int x:arrayList){
                x--;
                if (x>0){
                    priorityQueue.add(x);
                }
            }
            res += priorityQueue.size() == 0 ?cnt:cycle;
        }
        return res;
    }

猜你喜欢

转载自blog.csdn.net/u011010851/article/details/80475973
今日推荐