面试前【刷题】

文章目录

面经总结

1. 编程:股票最大利润

参考

public int maxProfit(int[] prices) {
        int minprice = prices[0];
        
        int maxProfit =0;
        for(int i=1; i<prices.length;i++){
            int min = Math.min(minprice, min);
            maxProfit = Math.max(maxProfit, prices[i]-min);
        }
        return maxProfit;
    }
2. 算法.数组中出现次数超过一半的数字

参考

public int majorityElement(int[] nums) {
        Arrays.sort(nums);
        return nums[nums.length/2];
    }
3. 自己创建一个单链表,返回中间结点的值
 >先求size,然后求出中间的位置,遍历得到中间节点。
4. 算法题青蛙跳格子

参考

public int numWays(int n) {
        if(n <=1) return 1;
        int[] arr = new int[n+1];
        arr[0] = 1;
        arr[1] = 1;

        for (int i=2;i<arr.length;i++){
            arr[i] = arr[i-1] + arr[i-2];
            arr[i] %= 1000000007;
        }
        return arr[n];
    }
5. 算法题:罗马字符转整数

参考

public int romanToInt(String s){
        int pre =getChar(s.charAt(0) );
        int sum =0;
        // 如果左边比右边小,就前一个作为负数
        // for循环是加减前一个元素
        for(int i=1; i<s.length(); i++){
            int num = getChar(s.charAt(i));
            if( num > pre)
                sum -= pre;
            else 
                sum += pre;
            pre = num;
        }
        //前面的循环,没有加上最后一个元素,所以现在要加上最后一个元素
        sum += pre;
        return sum;
    }

    public int getChar(char c){
        switch (c){
            case 'I': return 1;
            case 'V': return 5;
            case 'X': return 10;
            case 'L': return 50;
            case 'C': return 100;
            case 'D': return 500;
            case 'M': return 1000;
            default : return 0;
        }
    }
6. 两个list合并成一个有序无重复的list

参考:把相等的时候单独拿出来即可

public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
        if(l1 == null) return l2;
        if(l2 == null) return l1;
        ListNode l = null;
        if(l1.val <= l2.val){
            l = l1;
            l.next = mergeTwoLists(l1.next, l2);
        }else {
            l=l2;
            l.next = mergeTwoLists(l1, l2.next);
        }
        return l;
    }
7. 二叉树的遍历

参考

8. 算法题:一个排列好的数组输出所有不相同数字的个数
 >用set
9. 算法题:输入{’‘abc’’,’‘bac’’,’‘cab’’,’‘atc’’,’‘act’’,’‘aac’’,’‘fbc’’};

输出二维数组每一行为相同字母拼接成的字符串{{’‘abc’’,’‘bac’’,’‘cab’’},{’‘atc’’,’‘act’’
},{’‘aac’’},{’‘fbc’’}}
利用排序,然后hashmap

public List<List<String>> groupAnagrams(String[] strs) {
        //先对每个字符排序,然后相同的则为一组,需要map做映射
        HashMap<String, List> map = new HashMap<>();
        // String存储排序好的字符串,list存储原数组中的乱序元素,一一对应
        for(String str:strs){
            char[] ch = str.toCharArray();
            Arrays.sort(ch);
            String temp = String.valueOf(ch);
            if(!map.containsKey(temp)) map.put(temp,new ArrayList());
            map.get(temp).add(str);
        }
        return new ArrayList(map.values());
    }
10. 按序增长的一个数组求出小于m的最大的数

参考

11. 一个链表中删除一个值返回这个链表

参考

public class LinkListUtli {
	public static void deleteNode(LNode L,LNode p)
	{
		if(p==null||L==null) return;//如果p为空或单链表L为空不符合题意,直接返回
		if(p.next != null) //如果p不是最后一个结点
		{
			LNode q=p.next;//q为p的后继结点
		    p.data=q.data;
		    p.next=q.next;//从单链表中删除结点q
		}
		else //如果p是最后一个结点
		{
			LNode pre=L;//用pre表示p的前驱结点
			while(pre.next != null) //保持pre有后继结点
			{
				if(pre.next==p)//如果pre是p的前驱结点
				{
					pre.next=p.next;//将结点p从单链表中删除
				}
			}
		}
		
	}
}
12. 单例设计模式

详细介绍参考
>饿汉式:三步走,创建时直接实例化
懒汉式:修改上面

13. 快排

代码参考

14. 排序算法及时间复杂度,写快排,快排是否稳定

参考
冒泡排序
快排
排序算法稳定性的理解
插入排序法
选择排序算法
归并排序
堆排序算法

15. 手撕代码:给一个字符串,找出最长的不重复的子串;

参考

public int lengthOfLongestSubstring(String s) {
        //滑动窗口法
        HashMap<Character, Integer> map = new HashMap<>();
        int left =0;//窗口的起始位置
        int max =0; //窗口的最大长度,每次都要比较原窗口的最大长度和新窗口的长度,返回较大的那一个窗口
        for (int i=0; i<s.length(); i++){
            if(map.containsKey(s.charAt(i))){
                // 如果map中有这个元素了,说明有重复元素,则需要移动窗口,到不包含这个重复元素,且需要注意窗口不能会退,所以需要max函数保证窗口不回退
                left = Math.max(left, map.get(s.charAt(i))+1);
                //如果没有max,类似abba这种情况,到最后一个元素a的时候,会使得left = 1,导致窗口回退,那样就包括了重复元素b
            }
            map.put(s.charAt(i), i);
            max = Math.max(max, i-left+1);
        }
        return max;    
    }
16. 手撕代码:力扣41 困难难度,缺失的第一个整数

参考

17. 对含有重复数字的数组去重并排序

去重参考
>可以用hashset么

18. 最大不重复子串,说思路,时间复杂度

参考

19. 输入一个字符串,如“127.0.0.1”,判断是否是十进制表示的ipv4地址
20. 输入一个数组{1,2,3,2,2,4,4,1};输出数组中数字重复出现的最大次数,写出它的测试用例
  >注意hashmap的遍历~以及包装类和基本数据类型的拆箱和装箱
21. 代码题:滑动窗口最大值

参考

22. 给定一个数组,求和为s的所有子数组

参考一
参考二

23. 代码题:两个字符串求最长公共子串
24. 字符串变形。“Hello World"变形后就变成了"wORLD hELLO”

参考

考前必刷

1. 反转链表

反转链表

public ListNode ReverseList(ListNode head){
        //需要三个节点之间得交换来反转链表
        ListNode pre=null;
        ListNode next=null;
        while(head!=null){//head没到null就说明,head指向得不是最后一个节点,就要一直交换
            next=head.next;//首先head指向得是当前节点,那么在最开始head是头节点得时候,pre=null没问题,但是next不应该是null,所以先给next赋值
            head.next=pre;//head是当前节点,因为要反转链表,所以当前节点得next应该是前一个节点,也就是pre
            pre=head; //前两行代码就算转换完毕了,接下来就是移动节点,所有得节点后移,pre就应该是刚才得当前节点
            head=next; //next应该给当前节点赋值
        }
        return pre;
        //最终返回得应该是pre,因为当head指向到最后一个节点的时候,head并不是null,循环执行以后,head指向了null,
        // 在判断发现循环条件不满足,
        // 但是此时的head指向的是null,pre才是最后一个节点,也就是现在的头节点,所以返回pre
    }
2. 递归:斐波那切数列简单

递归:斐波那切数列简单

3. 递归:两个链表合并递归

递归:两个链表合并递归

public ListNode Merge(ListNode list1,ListNode list2){
        ListNode list=null;
        if(list1==null){
            return list2;
        }else if(list2==null){
            return list1;
        }

        if(list1.val<=list2.val){
//            list.val=list1.val;
            list=list1;  // 上面那样写法不对,因为list最开始是null,所以不存在val,你要直接将list1给list,然后再修改next得值
            list.next=Merge(list1.next,list2);
        }
        if(list1.val>list2.val){
//            list.val=list2.val;
            list=list2; // 上面那样写法不对,因为list最开始是null,所以不存在val,你要直接将list2给list,然后再修改next得值
            list.next=Merge(list1,list2.next);
        }
        return list;
    }
4. 栈

5. 二叉树打印

二叉树打印

6.链表深拷贝

链表深拷贝

7. 回溯法:全排列

回溯法:全排列

List<List<Integer>> res = new ArrayList<>(); 
    public List<List<Integer>> permute(int[] nums){
        int len = nums.length;
        if(len == 0) return res;
        boolean used[] = new boolean[len];
        List<Integer> path = new ArrayList<>();
        dfs(nums,len,0,used,res,path);
        return res;
    }

    public void dfs(int[] nums, int len, int depth, boolean[] used, List<List<Integer>> res, List<Integer> path){
        if(depth == len){
            res.add(new ArrayList<>(path));  //如果路径中的参数到了3个,就可以将这个路径存到最后的结果当中了
        }

        //开始回溯
        for(int i =0; i<len; i++){
            if(!used[i]){ //如果数字没用过,则将这个数字存入到path中,同时记得将used[i]修改为已使用
                path.add(nums[i]);
                used[i] = true;
                dfs(nums, len, depth+1, used, res, path); //然后递归下一个位置的数字,同样使用这个方法
                // 回溯法,一次的path记录完成以后,要回溯到上一个状态
                // 注意:这里是状态重置,是从深层结点回到浅层结点的过程,代码在形式上和递归之前是对称的
                used[i] = false;
                path.remove(path.size()-1);
            }
        }
    }

回溯法:子集
回溯法:子集(有重复元素)
回溯:组合总和

8. 最大连续子序列的和

最大连续子序列的和

public int FindGreatestSumOfSubArray(int[] array) {
        int[] dp = new int[array.length];
        dp[0]=array[0];
        int result =dp[0];
        for(int i = 1;i<array.length;i++){
            dp[i] = Math.max(dp[i-1]+array[i],array[i]);
            result = Math.max(dp[i],result);
        }
        return result;
    }
9. 找到第一个只出现一次的字符

找到第一个只出现一次的字符,

10. 求二叉树深度

求二叉树深度

11. 和为S的连续正数序列

和为S的连续正数序列

12. 扑克牌构成顺子

扑克牌构成顺子

13.链表环的入口节点

链表环的入口节点

public ListNode EntryNodeOfLoop(ListNode pHead){
        if(pHead == null){
            return null;
        }
        //先判断是否有环,
        boolean isHuan=false;  //默认不是环
        ListNode slow=pHead;
        ListNode fast=pHead;
        while (fast!=null&&fast.next!=null){  //没环的链表,就是fast和fast.next最终会为null
            slow=slow.next;
            fast=fast.next.next;
            if(slow==fast){
                isHuan=true;
                break;
            }
        }
        if(isHuan==false){
            return null;
        }else {
            //找环的个数,从刚才的那个节点开始,再回到这个节点,就是环的个数了
            int count = 1;
            fast = fast.next;
            while (fast != slow) {
                count++;
                fast=fast.next;
            }
            //然后让一个指针从头开始,另一个从count开始,相遇就是环的首节点
            fast=pHead;
            slow =pHead;
            for(int i=0;i<count;i++){
                fast=fast.next;
            }
            while (fast!=slow){
                fast=fast.next;
                slow=slow.next;
            }
        }
        return fast;
    }
14.矩阵中路径

矩阵中路径

请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。路径可以从矩阵中的任意一格开始,每一步可以在矩阵中向左、右、上、下移动一格。如果一条路径经过了矩阵的某一格,那么该路径不能再次进入该格子。例如,在下面的3×4的矩阵中包含一条字符串“bfce”的路径(路径中的字母用加粗标出)。
[[“a”,“b”,“c”,“e”],
[“s”,“f”,“c”,“s”],
[“a”,“d”,“e”,“e”]]
但矩阵中不包含字符串“abfb”的路径,因为字符串的第一个字符b占据了矩阵中的第一行第二个格子之后,路径不能再次进入这个格子。
代码

class Solution {
    public boolean exist(char[][] board, String word) {
        char[] words = word.toCharArray();
        for(int i = 0; i < board.length; i++) {
            for(int j = 0; j < board[0].length; j++) {
                if(dfs(board, words, i, j, 0)) return true;
            }
        }
        return false;
    }
    boolean dfs(char[][] board, char[] word, int i, int j, int k) {
        if(i >= board.length || i < 0 || j >= board[0].length || j < 0 || board[i][j] != word[k]) return false;
        if(k == word.length - 1) return true;
        char tmp = board[i][j];
        board[i][j] = '/';
        boolean res = dfs(board, word, i + 1, j, k + 1) || dfs(board, word, i - 1, j, k + 1) || 
                      dfs(board, word, i, j + 1, k + 1) || dfs(board, word, i , j - 1, k + 1);
        board[i][j] = tmp;
        return res;
    }
}
15. 只出现一次的数字

只出现一次的数字

16. 股票最大利润

股票最大利润
股票问题

// https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-ii/solution/best-time-to-buy-and-sell-stock-ii-zhuan-hua-fa-ji/
     //贪心算法,每次得到局部最优解
  //  该算法仅可以用于计算,但计算的过程并不是真正交易的过程,但可以用贪心算法计算题目要求的最大利润。
    public int maxProfit(int[] prices) {
        int res =0;
        for(int i =0; i<prices.length-1;i++){
            int temp = prices[i+1]-prices[i];
            if(temp > 0) res = res + temp;
        }
        return res;
    }
17. 判断子串

判断子串
给定字符串 s 和 t ,判断 s 是否为 t 的子序列。

public boolean isSubsequence(String s, String t) {
        //采用双指针法
        int i =0;
        int j=0;
        while (i<s.length() && j<t.length()){
            if(s.charAt(i) == t.charAt(j))
                i++;
            j++;
        }
        return i==s.length();
    }
18. 打家劫舍

打家劫舍
打家劫舍二

19. 有效括号

有效括号

20.回文字符串

回文字符串
给定一个非空字符串 s,最多删除一个字符。判断是否能成为回文字符串。

public boolean validPalindrome(String s) {
        char[] arr = s.toCharArray();
        int left = 0;
        int right = arr.length-1;
        while (left <= right){
            if(arr[left] == arr[right]){
                left++;
                right--;
            }else{
                boolean flag1=true;
                boolean flag2=true;
                //然后分两种情况去计算[left+1,right]和[left,right-1],为了不轻易改变left和right,我们多引入变量i和j
                for(int i=left+1,j=right;i<=j;i++,j--){
                    if(arr[i] != arr[j]){
                        flag1 = false;
                        break;
                    }
                }
                for(int i=left,j=right-1;i<=j;i++,j--){
                    if(arr[i] != arr[j]){
                        flag2 = false;
                        break;
                    }
                }
                return flag1 || flag2;
            }

        }
     return true;
    }

回文子串

输入:“abc”
输出:3
解释:三个回文子串: “a”, “b”, “c”

public int countSubstrings(String s) {
        int res =0;
        for(int center=0; center<s.length()*2-1; center++){
            int left = center/2;
            int right = left + center%2;
            while (left >=0 && right<s.length() && s.charAt(left) == s.charAt(right)){//这个得用while,因为while才能一直往外扩散
            // if (left >=0 && right<s.length() && s.charAt(left) == s.charAt(right)){
                res++;
                left--;
                right++;
            }
        }
        return res;
    }

最长回文子串

输入: “babad”
输出: “bab”
注意: “aba” 也是一个有效答案。

public String longestPalindrome(String s) {
        // 在回文子串那题的基础上修改
        String res = "";
        for(int center = 0; center<2*s.length()-1; center++){
            int left = center/2;
            int right = left + center%2;
            while (left >=0 && right<s.length() && s.charAt(left) == s.charAt(right)){ //记住这一定得是while,因为要不断的 移动的,直到不是回文才不移动
                String temp = s.substring(left,right+1);  // 把每次的回文子字符串先暂时保存,如果最常则应当返回这个
                if(temp.length() > res.length())
                    res = temp;
                left--;
                right++;
            }
        }
        return res;
    }
21. 无重复最长子串

无重复最长子串

22.最短无序连续子数组

最短无序连续子数组

输入: [2, 6, 4, 8, 10, 9, 15]
输出: 5
解释: 你只需要对 [6, 4, 8, 10, 9] 进行升序排序,那么整个表都会变为升序排序。

public int findUnsortedSubarray(int[] nums) {
        int[] snums = nums.clone();
        Arrays.sort(snums);
        int start = nums.length-1;
        int end = 0;
        for(int i=0;i<nums.length;i++){
            if(snums[i] != nums[i]){
                start = Math.min(start, i);
                end = Math.max(end, i);
            }
        }
        return end-start >0? end-start+1:0;
    }

非递减数列

23. 动态规划:最小路径和

动态规划:最小路径和

输入:
[
[1,3,1],
[1,5,1],
[4,2,1]
]
输出: 7
解释: 因为路径 1→3→1→1→1 的总和最小。

public int minPathSum(int[][] grid) {
        //https://leetcode-cn.com/problems/minimum-path-sum/solution/zui-xiao-lu-jing-he-by-leetcode/
        int[][] dp = new int[grid.length][grid[0].length];
        for(int i=grid.length-1;i>=0;i--){
            for(int j=grid[0].length-1;j>=0;j--){
                if(i == grid.length-1 && j!=grid[0].length-1)
                    dp[i][j] = grid[i][j] + dp[i][j+1];
                else if(i!=grid.length-1 && j==grid[0].length-1)
                    dp[i][j] = grid[i][j] + dp[i+1][j];
                else if(i!=grid.length-1 && j!=grid[0].length-1)
                    dp[i][j] = grid[i][j] + Math.min(dp[i+1][j],dp[i][j+1]);
                else 
                    dp[i][j] = grid[i][j];
            }
        }
        return dp[0][0];
    }

动态规划:不同路径
问总共有多少条不同的路径?

public int uniquePaths(int m, int n) {
        //https://blog.youkuaiyun.com/weixin_44550963/article/details/107282087
        //f(i,j) = f(i,j-1) + f(i-1,j)
        int[][] dp = new int[m][n];
        for(int i=0;i<m;i++){
            for(int j=0;j<n;j++){
                if(i==0 || j==0) dp[i][j] = 1;  //第一行或者第一列,只有一种横着走 或者竖着走一种可能
                else dp[i][j] = dp[i-1][j] + dp[i][j-1];
            }
        }
        return dp[m-1][n-1];
    }
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值