【坚持】LeetCode Top Interview Questions 2

文章目录

  • 一、知识点
    • 1.1 算法与数据结构
      • 贪心算法
      • 动态规划
      • 回溯
      • 滑动窗口
    • 1.2 编程
      • 最大值最小值
      • List
      • Arrays
      • Collections
      • String, StringBuilder, StringBuffer你还没掌握全!
      • PriorityQueue
      • next()与nextLine()的区别
      • 大问题:一不留神就用==比较字符串了
      • Comparator, Comparable 细节真的多
  • 二、题
    • 2.1 分类好的经典必刷题
    • 2.2 日常
      • 鸡鸭分类问题
      • 笔试,要善用接口。。。
      • 3.28 剑指完整刷,只记失败
        • (8)删除链表重复结点,一个不留(实战惨烈)
        • (12)数据流中的中位数(大顶堆小顶堆)
        • (13)滑动窗口的最大值(双端队列)
        • (18)二叉搜索树 ==》双向链表
        • (19)字符串的排列——最好的题
        • (21)两个链表第一个公共结点
        • (23)判断平衡二叉树
    • 2.3 真实笔试
      • 【招行——配袜子,有长度和重量的木棒】
      • 【百度——DP之背包问题;大局观/化繁为简问题】
      • 【度小满——有完整题目,有我的答案】
    • 2.4 力扣TOP100
      • 11 盛最多水的容器
      • 15 三数之和
      • 17 电话号码的字母组合
      • 19 删除链表倒数第k个结点
      • 338 比特位计数
      • 448 找到所有数组中消失的数字 ♥
      • 461 汉明距离 ×

一、知识点

1.1 算法与数据结构

贪心算法

局部最优解 --> 全局最优解,部分情况才成立
所以用不用贪心,要自己分析题目

动态规划

知乎 - DP问题见一个杀一个!
步骤一、定义数组元素的含义
步骤二、找出关系数组元素间的关系式
步骤三、找出初始值

90% 的字符串问题都可以用动态规划解决,并且90%是采用二维数组。
动态规划求解问题的四个特征:
①求一个问题的最优解;
②整体的问题的最优解是依赖于各个子问题的最优解;
③小问题之间还有相互重叠的更小的子问题;
④从上往下分析问题,从下往上求解问题;

回溯

为啥叫回溯法?
用了递归,退出来的时候还原条件。
递归,有的时候需要回溯,有的时候不回溯——如果有一个公共变量,你改了,但别人还要原来的,那就回溯;否则不回溯,就是普通递归就完了。
使用回溯一般就不直接return下一层了,判断条件符合再return下一层,在最后面写回溯和return。
不用回溯:
机器人运动范围
用回溯:
剑指 – 矩阵中的路径
剑指 – 字符串的排列
剑指 – 二叉树中和为某值的路径
力扣 - 39.组合总和(中等)

滑动窗口

力扣中等 - 无重复字符的最长子串

剑指Offer – 滑动窗口的最大值(此滑窗非彼滑窗)

1.2 编程

最大值最小值

Integer.MAX_VALUE
Integer.MIN_VALUE

List

拷贝已有List:

List<Integer> copy = new ArrayList<>(list);

Arrays

Arrays.toString()
Arrays.sort()
Arrays.asList(1,2,3,4) 返回List

String[] s = {
     "aa","bb","cc"};
List<String> strlist = Arrays.asList(s);

注意:基本类型数组不能作为asList的输入参数,否则会引起程序逻辑混乱。

Collections

String, StringBuilder, StringBuffer你还没掌握全!

str.substring(a, b) 可以省略结束位置,注意substring没大写!
str.charAt(index) 有它数组都不用转了
str.contains() 有时int换String就为了它
sb.setLength(len)
sb.setCharAt(index, 'char')

StringBuilder常用方法如下:

StringBuilder sb = new StringBuilder();
sb.setLength(10);
int len = sb.length();
char c = sb.charAt(3);
sb.setCharAt(4, 'x');
String s = sb.toString();

PriorityQueue

next()与nextLine()的区别

大问题:一不留神就用==比较字符串了

equals()

Comparator, Comparable 细节真的多

Comparator – compare(Object o1, Object o2) – java.util
Comparable – compareTo(Object o) – java.long
注意,Comparator要写明泛型!!!

Collections.sort(list, new Comparator<Integer>(){
     
	public int compare(Integer t1, Integer t2){
     
		return t2-t1; //默认是升序,这样就改成降序了
	}
});

compare的细节:1)public不能少;2)形参Integer不能写成int!
注意,compare和compareTo的返回类型都是int!

二、题

2.1 分类好的经典必刷题

大神为你列好清单了

2.2 日常

鸡鸭分类问题

农场有n只鸡鸭排为一个队伍,鸡用“C”表示,鸭用“D”表示。当鸡鸭挨着时会产生矛盾。需要对所排的队伍进行调整,使鸡鸭各在一边。每次调整只能让相邻的鸡和鸭交换位置,现在需要尽快完成队伍调整,你需要计算出最少需要调整多少次可以让上述情况最少。例如:CCDCC->CCCDC->CCCCD这样就能使之前的两处鸡鸭相邻变为一处鸡鸭相邻,需要调整队形两次。

解:我觉得有点像动态规划思想?
你被难住是因为移动到哪个位置不确定,鸡和鸭掺和着,可能左可能右……
其实,动态规划,开始做了以后,就不难确定了
1)鸡左还是鸭左,需要求出来比(可以放在一个循环里求)
2)比如鸡左时,想求当前鸡左移次数,只要保证,最左端是连续鸡,那就是用连续鸡右端和该当前鸡位置就能求出来位移次数!

笔试,要善用接口。。。

Arrays.sort() 数组排序不是题目重点,就用这个排!
String.contains() 有时候愿意把int换成String,就为了用这个方法。。。

3.28 剑指完整刷,只记失败

(1)求1+2+3+…+n
要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句(A?B:C)。
Java用到关系运算,那肯定是个布尔值啊

(2)不用加减乘除做加法
注意条件是不等于0!不要写成>0!

(3)字符串转整数
放越界方法:因为变量乘10倍或加个位数时都有可能越界,所以检查方式转换为让极限值除以10,减个位数!
Integer的取值范围(-2^31 ~ 2^31-1)
首位特殊,先判断,有:数字,±,其他
后面的,必须数字,需要溢出判断,正数负数最大值不一样
Integer.MAX_VALUE
Integer.MIN_VALUE
答案中,正数时负过来算,最后反回去,这样可以两种情况一起算。

(4)数组中重复的数字(不用hash)
掌握O(1)方法

(5)构建乘积数组
又忘了,一看答案秒会。记住呗

(6)正则表达式匹配
情况多,用循环太麻烦了,那就递归。

(7)字符流中第一个不重复的字符
呃。。无关JavaIO

(8)删除链表重复结点,一个不留(实战惨烈)

没有高级算法,就是基本题,你倒是会啊
有个亮点,如果头节点就是重复的怎么办?
看完答案亲手写一遍没写出来233333

(9)之字形打印树
注意考虑进去特殊情况:
栈里可能掺着空值,只要判断一下是空的就直接扔掉就好了;
判断下子队列是不是空的,空的就不用加进结果了,也说明结束了。

(10)二叉树打印成多行
进阶的层次遍历
照(9)画(10)
超时了。你以为是算法不行,其实是你代码写成死循环了

(11)序列化,反序列化二叉树
普通先序不能知道树结构,但如果空值都在序列里,那就可以建树了啊!
还整出个经典问题——比较字符串内容别用==

(12)数据流中的中位数(大顶堆小顶堆)

PriorityQueue
Comparatorcompare

(13)滑动窗口的最大值(双端队列)

队首记录当前最大值,过期就弹出去;
每次滑动把新数和队尾数比,小的都扔掉,最后把新数加进来;
指针位置大于窗口的时候,才开始把队首加进答案里。

(14)机器人的运动范围
总是错那么一点细节,明明会做

(15)替换字符串空格——StringBuilder两个基本方法

(16)调整数组让奇数在偶数前,相对顺序不变
1)插入排序,时间复杂度高;
2)辅助数组,时间复杂度低。

(17)顺时针打印矩阵
复杂,难。

(18)二叉搜索树 ==》双向链表

代码很简单,怎么我们想得复杂???
中序遍历,已经帮我们做了一些事了。

(19)字符串的排列——最好的题

回溯法。

(20)丑数———重复值啊啊啊啊啊!!!!

(21)两个链表第一个公共结点

掌握空间复杂度O(1)方法

(22)统计一个数字在排序数组中出现的次数。
关键的判定条件

(23)判断平衡二叉树

最简单(复杂度高一点)的递归方法要会吧!!!!

2.3 真实笔试

【招行——配袜子,有长度和重量的木棒】

(1)配袜子
非0加1
哦,你不是非0加1 。。。
好吧,技不如人,只能认了
我们不是输入输出的问题!是我们做的不对!
可能第一例错了,后面就都错了。
我们自测用例在牛客上能过,就不要怀疑输入输出了

(2)有长度和重量的木棒
可以百度出来。。。
木材加工问题
很贪心的一道题。为木材创建类,继承Comparable接口,排好序。。。就不难。

【百度——DP之背包问题;大局观/化繁为简问题】

1)翻硬币

桌子上放着N枚硬币,将其从1到N编号,初始时有的正面朝上,有的反面朝上。现在要将所有硬币翻至正面朝上,每次可以选择一个区间[L,R](1≤L≤R≤N),并执行以下两种操作中的一种:
①将编号为L到R的硬币翻面;
②若编号为L到R的硬币均反面朝上,则将其翻至正面朝上。
其中操作①所需的代价为x,操作②所需的代价为y,那么将所有硬币翻至正面朝上所需的总代价最小是多少?
输入
第一行包含三个整数N、x和y,1≤N≤105,1≤x,y≤10。
第二行包含N个空格隔开的整数t1到tN,0≤ti≤1。若ti=0,则表示i号硬币初始时反面朝上;若ti=1,则表示i号硬币初始时正面朝上。
输出
输出总代价的最小值。
样例输入
3 1 2
0 1 0
样例输出
2
提示
第一次选择区间[1,3]并执行操作①,第二次选择区间[2,2]并同样执行操作①。

这个提示很狗,如果按提示思路,应该会很复杂。
不要盲目迷信提示!
大局观/看本质/化繁为简:

因为翻的是一个区间,所以连续的0=单个0,连续的1=单个1!
对[10]而言:就相当于翻[0],无论用哪个方法;
对[01]而言:就相当于翻[0],无论用哪个方法;
总之,没必要翻1,肯定赚不到,和只翻0等价。
因为目的翻0,所以取[01]而非[10],并且末尾如果是[0]注意也算上。
这样根本上就是数了有几堆0,然后方法1和方法2都是一样作用的翻面,选代价小的就行了。

2)取数

首先给出n个数字a1,a2,….an,然后给你m个回合,每回合你可以从中选择一个数取走它,剩下来的每个数字ai都要减去一个值bi。如此重复m个回合,所有你拿走的数字之和就是你所得到的分数。
现在给定你a序列和b序列,请你求出最多可以得到多少分。
输入
输入第一行,仅包含一个整数n(1<=n<=100),表示数字的个数。
第二行,一个整数m(1<=m<=n),表示回合数。
接下来一行有n个不超过10000的正整数,分别为a1,a2…an.
最后一行有n个不超过500的正整数,分别为b1,b2….bn.
输出
输出仅包含一个正整数,即最多可以得到的分数
样例输入
5
5
10 20 30 40 50
4 5 6 7 8
样例输出
100

【度小满——有完整题目,有我的答案】

1)
滑动窗口
时间限制:C/C++语言 1000MS;其他语言 3000MS
内存限制:C/C++语言 65536KB;其他语言 589824KB
题目描述:
在机器学习中有一种流行的池化操作,而在池化操作中,33极大值池化应用十分广泛。什么是33极大值池化呢?设原矩阵是nm的,则33极大值池化就是枚举矩阵中的所有33的子矩阵,分别求最大值并顺次拼接而成,处理过后的矩阵是(n-2)(m-2)。

例如,原矩阵是[[1,2,3,4],[5,6,7,8],[9,10,11,12]],经过池化之后就变成[[11,12]]。

为了提高难度,选择的滑动窗口并不是33的,而是ab的,由于输入可能是非常大的,原nm的矩阵权值由以下公式计算得到,h(i,j)=ij mod 10。(1<=i<=n,1<=j<=m)

由于输出矩阵也是一个很麻烦的事情,因此你只需输出经过a*b池化处理后的矩阵的元素之和即可。

输入
输入第一行包含四个正整数,n,m,a,b,分别表示原矩阵的行列数量和滑动窗口的行列数量。(1<=n,m,a,b<=1000)

输出
输出仅包含一个整数,即新矩阵的元素之和。

样例输入
4 5 3 3
样例输出
54

2)
传送门
时间限制:C/C++语言 1000MS;其他语言 3000MS
内存限制:C/C++语言 65536KB;其他语言 589824KB
题目描述:
西西所在的国家有N座城市,每座城市都有一道传送门,城市 i 的传送门通往城市 a[i]。当西西位于城市 i 时,每次他可以执行以下三种操作中的一种:

花费 A 的费用,从城市 i 前往城市 a[i];

如果 a[i] > 1,可以花费 B 的费用,将 a[i] 的值减少 1;

如果 a[i] < N,可以花费 C 的费用,将 a[i] 的值增加 1。

现在,西西想从城市 1 前往城市 N,那么他至少要花费多少费用?

输入
第一行输入四个整数 N、A、B、C(1 < N <= 10000,1 <= A、B、C <= 100000)。

第二行输入 N 个整数 a[1] 到 a[N](1 <= a[i] <= N)。

输出
输出一个整数,表示从城市 1 前往城市 N 所花费的最少费用。

样例输入
7 1 1 1
3 6 4 3 4 5 6
样例输出
4

提示
样例解释
西西可以按顺序执行以下操作:
将 a[1] 减少 1,此时 a[1] = 2;
从城市 1 前往城市 2;
将 a[2] 增加 1,此时 a[2] = 7;
从城市 2 前往城市 7。

2.4 力扣TOP100

11 盛最多水的容器

挺像dp,然而是双指针

15 三数之和

这题不会不应该
Arrays.asList()很关键

17 电话号码的字母组合

回溯法
正确写法:

backtrack(comb+letter, digits.substring(1));
//结果:
["ad","ae","af","bd","be","bf","cd","ce","cf"]

我的写法:

comb = comb + letter;
backtrack(comb, digits.substring(1));
//结果:
["ad","ade","adef","abd","abde","abdef","abcd","abcde","abcdef"]

分析:
正确写法中,对同一层递归而言,comb是一样的;
而你的写法,把comb改了,递归变得很混乱。
同类问题:22 括号生成

19 删除链表倒数第k个结点

弟弟题

338 比特位计数

乘2相当于左移,除以2相当于右移!!!

448 找到所有数组中消失的数字 ♥

461 汉明距离 ×

你可能感兴趣的:(Java)