1

所有类型面试题集合

1. 冒泡排序实现及复杂度

算法思想:每次比较相邻的两个元素,一直到数组末尾,这样一组操作每次会确定最大位置的元素;重复操作每次将剩下元素中较大的元素交换到数组后面,直到所有元素都确定好位置。
复杂度分析:平均O(n^n),最好O(n),最坏O(n^2)。
稳定性:稳定。
代码模板:

class Solution {
    public void bubbleSort(int[] nums) {
        for (int i = 0; i < nums.length; i++) {
            for (int j = 0; j < nums.length - i - 1; j++) {
                if (nums[j] > nums[j + 1]) {
                    swap(nums, j, j + 1);
                }
            }
        }
    }

    private void swap(int[] nums, int p, int q) {
        int tmp = nums[p];
        nums[p] = nums[q];
        nums[q] = tmp;
    }
}

2. 归并排序实现及复杂度

归并排序的思想详解
自己之前总结的各种排序
算法思想: 先拆分再合并。
复杂度分析:平均O(nlogn),最好O(nlogn),最坏O(nlogn)。
稳定性:稳定。
代码模板:

class Solution {
    public void mergeSort(int[] nums, int start, int end) {
        if(start<end){
            int mid = (start + end) / 2;
            mergeSort(nums, start, mid);
            mergeSort(nums, mid + 1, end);
            merge(nums, start, mid, end);
        }
    }

    private void merge(int[] nums, int start, int mid, int end) {
        int p1 = start;
        int p2 = mid + 1;
        int index = start;
        int[] tmp = new int[nums.length];
        while (p1 <= mid && p2 <= end) {
            if (nums[p1] < nums[p2]) {
                tmp[index++] = nums[p1++];
            } else {
                tmp[index++] = nums[p2++];
            }
        }
        while (p1 <= mid) {
            tmp[index++] = nums[p1];
        }
        while (p2 <= end) {
            tmp[index++] = nums[p2++];
        }
        for (int i = start; i <= end; i++) {
            nums[i] = tmp[i];
        }
    }
}

3,快速排序实现及复杂度

快速排序的思想
快速排序会问到的问题
自己之前总结的各种排序
算法思想:采用了分治法和递归思想。首先找一个元素作为哨兵,再将大于它和小于它的分别放在右边和左边,这就确定了哨兵的位置。再依次排哨兵左边和右边的数组。
复杂度分析:平均O(nlogn),最好O(nlogn),最坏O(n^2)。
稳定性:不稳定。
代码模板:

class Solution {
    public void quickSort(int[] nums, int low, int high) {
        int p1 = low;
        int p2 = high;
        if (low < high) {
            int tmp = nums[low];
            while (p1 < p2) {
                while (p1 < p2 && nums[p2] > tmp) {
                    p2--;
                }
                if (p1 < p2) {
                    nums[p1] = nums[p2];
                    p1++;
                }
                while (p1 < p2 && nums[p1] < tmp) {
                    p1++;
                }
                if (p1 < p2) {
                    nums[p2] = nums[p1];
                    p2--;
                }
            }
            nums[p1] = tmp;
            quickSort(nums, low, p1 - 1);
            quickSort(nums, p1 + 1, high);
        } else {
            return;
        }
    }
}

TopK
这题直接应用快速排序模板先排序,再去前k个值。
但是力扣上有在快速排序上效率更高的思想,只排到前k个就行了,不用排之后的。

import java.util.Arrays;

class Solution {
    public int[] getLeastNumbers(int[] arr, int k) {
        quickSort(arr,0,arr.length-1);
        return Arrays.copyOf(arr,k);
    }
    private void quickSort(int[] nums, int low, int high) {
        int p1 = low;
        int p2 = high;
        if (low < high) {
            int tmp = nums[low];
            while (p1 < p2) {
                while (p1 < p2 && nums[p2] > tmp) {
                    p2--;
                }
                if (p1 < p2) {
                    nums[p1] = nums[p2];
                    p1++;
                }
                while (p1 < p2 && nums[p1] < tmp) {
                    p1++;
                }
                if (p1 < p2) {
                    nums[p2] = nums[p1];
                    p2--;
                }
            }
            nums[p1] = tmp;
            quickSort(nums, low, p1 - 1);
            quickSort(nums, p1 + 1, high);
        } else {
            return;
        }
    }
}

4.动态规划

【背包思想可解的Leetcode题】
目标和

分割等和子集

零钱兑换

零钱兑换II

组合总和

5.回溯法

全排列

import java.util.*;

class Solution {
    /**
     * 全排列
     *
     * @param nums
     * @return
     */
    public List<List<Integer>> permute(int[] nums) {
        List<List<Integer>> ans = new ArrayList<>();
        LinkedList<Integer> path = new LinkedList<>();
        boolean[] used = new boolean[nums.length];
        backtrack(nums, ans, 0, path, used);
        return ans;
    }

    /**
     * 回溯法
     *
     * @param nums
     * @param ans
     * @param i
     * @param path
     * @param used
     * @return
     */
    private void backtrack(int[] nums, List<List<Integer>> ans, int depth, LinkedList<Integer> path, boolean[] used) {
        if (depth == nums.length) {
            ans.add(new ArrayList<>(path));
            return;
        }
        for (int i = 0; i < nums.length; i++) {
            if (used[i]) {
                continue;
            }
            path.addLast(nums[i]);
            used[i] = true;
            backtrack(nums, ans, depth + 1, path, used);
            path.removeLast();
            used[i] = false;
        }
    }
}

目标和

class Solution {
    private int count = 0;

    public int findTargetSumWays(int[] nums, int S) {
        backtrack(nums, S, 0);
        return count;
    }

    /**
     * 回溯法
     * @param nums
     * @param rest
     * @param i
     */
    private void backtrack(int[] nums, int rest, int i) {
        if (i == nums.length) {
            if (rest == 0) {
                count++;
            }
            return;
        }
        rest -= nums[i];
        backtrack(nums, rest, i + 1);
        rest += nums[i];

        rest += nums[i];
        backtrack(nums, rest, i + 1);
        rest -= nums[i];
    }
}

组合总和

import java.util.*;

class Solution {
    public List<List<Integer>> combinationSum(int[] candidates, int target) {
        List<List<Integer>> ans = new ArrayList<>();
        LinkedList<Integer> sub = new LinkedList<>();
        Arrays.sort(candidates);
        backtrack(candidates, target, 0, ans, sub);
        return ans;
    }

    /**
     * 回溯法&剪枝
     * @param candidates
     * @param rest
     * @param i
     * @param ans
     * @param sub
     */
    private void backtrack(int[] candidates, int rest, int i, List<List<Integer>> ans, LinkedList<Integer> sub) {
        if (rest == 0) {
            ans.add(new LinkedList<>(sub));
            return;
        }

        for (int k = i; k < candidates.length; k++) {
            if (rest - candidates[k] < 0) {
                break;
            }
            sub.add(candidates[k]);
            backtrack(candidates, rest - candidates[k], k, ans, sub);
            sub.removeLast();
        }
    }
}

组合总和 II(允许不同级不允许同级那里没看太懂)

import java.util.*;

class Solution {
    public List<List<Integer>> combinationSum2(int[] candidates, int target) {
        List<List<Integer>> ans = new ArrayList<>();
        LinkedList<Integer> sub = new LinkedList<>();
        Arrays.sort(candidates);
        backtrack(candidates, target, 0, ans, sub);
        return ans;
    }

    /**
     * 回溯法&剪枝
     *
     * @param candidates
     * @param rest
     * @param i
     * @param ans
     * @param sub
     */
    private void backtrack(int[] candidates, int rest, int i, List<List<Integer>> ans, LinkedList<Integer> sub) {
        if (rest == 0) {
            ans.add(new LinkedList<>(sub));
            return;
        }
        for (int k = i; k < candidates.length; k++) {
            if (rest - candidates[k] < 0) {
                break;
            }
            //允许不同级但不允许同级
            if (k > i && candidates[k] == candidates[k - 1]) {
                continue;
            }
            //加上当前的数
            sub.add(candidates[k]);
            backtrack(candidates, rest - candidates[k], k + 1, ans, sub);
            sub.removeLast();
        }
    }
}

全排列 II(同样是同级不同级那里)

import java.util.*;

class Solution {
    public List<List<Integer>> permuteUnique(int[] nums) {
        List<List<Integer>> ans = new ArrayList<>();
        LinkedList<Integer> sub = new LinkedList<>();
        boolean[] used=new boolean[nums.length];
        Arrays.sort(nums);
        backtrack(nums, used,0, ans, sub);
        return ans;
    }

    /**
     * 回溯法&剪枝
     *  @param nums
     * @param used
     * @param i
     * @param ans
     * @param sub
     */
    private void backtrack(int[] nums, boolean[] used, int i, List<List<Integer>> ans, LinkedList<Integer> sub) {
        if (sub.size() == nums.length) {
            ans.add(new LinkedList<>(sub));
            return;
        }
        for (int k = 0; k < nums.length; k++) {
            if(used[k]){
                continue;
            }
            //允许不同级但不允许同级
            if (k > 0 && nums[k] == nums[k - 1]&&used[k-1]) {
                continue;
            }
            //加上当前的数
            sub.add(nums[k]);
            used[k]=true;
            backtrack(nums, used, k + 1, ans, sub);
            used[k]=false;
            sub.removeLast();
        }
    }
}

子集

import java.util.*;

class Solution {
    public List<List<Integer>> subsets(int[] nums) {
        List<List<Integer>> ans=new ArrayList<>();
        LinkedList<Integer> sub=new LinkedList<>();
        backtrack(nums,ans,sub,0);
        return ans;
    }

    private void backtrack(int[] nums, List<List<Integer>> ans, LinkedList<Integer> sub, int i) {
        if(i==nums.length){
            ans.add(new LinkedList<>(sub));
            return;
        }
        sub.addLast(nums[i]);
        backtrack(nums,ans,sub,i+1);
        sub.removeLast();
        
        backtrack(nums,ans,sub,i+1);
    }
}

子集 II

import java.util.*;

class Solution {
    public List<List<Integer>> subsetsWithDup(int[] nums) {
        List<List<Integer>> ans = new ArrayList<>();
        LinkedList<Integer> sub = new LinkedList<>();
        Arrays.sort(nums);
        backtrack(nums, ans, sub, 0);
        return ans;
    }

    private void backtrack(int[] nums, List<List<Integer>> ans, LinkedList<Integer> sub, int i) {
            ans.add(new LinkedList<>(sub));
        for (int k = i; k < nums.length; k++) {
            if (k > i && nums[k] == nums[k - 1]) {
                continue;
            }
            sub.addLast(nums[k]);
            backtrack(nums, ans, sub, k + 1);
            sub.removeLast();
        }
    }
}

6.如何用链表实现栈


吃不完的土豆番茄
59 声望10 粉丝

引用和评论

1 篇内容引用
0 条评论