「这是我参与2022首次更文挑战的第1天,活动详情查看:2022首次更文挑战」。
LeetCode习题集 有些题可能直接略过了,整理一下之前刷leetcode
501. 二叉搜索树中的众数
给定一个有相同值的二叉搜索树(BST),找出 BST 中的所有众数(出现频率最高的元素)。
假定 BST 有如下定义:
结点左子树中所含结点的值小于等于当前结点的值 结点右子树中所含结点的值大于等于当前结点的值 左子树和右子树都是二叉搜索树 例如: 给定 BST [1,null,2,2],
1
\
2
/
2
返回[2].
提示:如果众数超过1个,不需考虑输出顺序
进阶:你可以不使用额外的空间吗?(假设由递归产生的隐式调用栈的开销不被计算在内)
PS:
遍历
要充分结合题目给的条件,因为是BST树,左结点都小于等于当前结点,右结点都大于等于当前结点
采用中序遍历,遍历整个树,
中序遍历:左->中->右
按照这种顺序遍历,相同的值结点一定是在一起遍历的
在遍历的过程中判断当前值的结点是否和左子树跟结点相等,
如果相等,当前值得出现次数+1
如果不相等就重新计算,当前值和当前值得出现次数
然后判断当前值得出现次数是否是和以前出现过值的最多的次数是相等,如果相等就把当前值加入到list
如果当前值的次数大于以前出现值的次数,直接清空list,当前值的出现次数是最大的
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
int preVal = 0, curTimes = 0, maxTimes = 0;
ArrayList<Integer> list = new ArrayList<Integer>();
public int[] findMode(TreeNode root) {
traversal(root);
int size = list.size();
int[] ans = new int[size];
for(int i = 0; i < size; i++){
ans[i] = list.get(i);
}
return ans;
}
//二叉搜索树中序遍历是递增顺序
public void traversal(TreeNode root){
if(root != null){
traversal(root.left);
//判断当前值与上一个值的关系, 更新 curTimes 和 preVal
if(preVal == root.val){
curTimes++;
}else{
preVal = root.val;
curTimes = 1;
}
//判断当前数量与最大数量的关系, 更新 list 和 maxTimes
if(curTimes == maxTimes){
list.add(root.val);
}else if(curTimes > maxTimes){
list.clear();
list.add(root.val);
maxTimes = curTimes;
}
traversal(root.right);
}
}
}
502. IPO
假设 力扣(LeetCode)即将开始其 IPO。为了以更高的价格将股票卖给风险投资公司,力扣 希望在 IPO 之前开展一些项目以增加其资本。 由于资源有限,它只能在 IPO 之前完成最多 k 个不同的项目。帮助 力扣 设计完成最多 k 个不同项目后得到最大总资本的方式。
给定若干个项目。对于每个项目 i,它都有一个纯利润 Pi,并且需要最小的资本 Ci 来启动相应的项目。最初,你有 W 资本。当你完成一个项目时,你将获得纯利润,且利润将被添加到你的总资本中。
总而言之,从给定项目中选择最多 k 个不同项目的列表,以最大化最终资本,并输出最终可获得的最多资本。
示例 1:
输入: k=2, W=0, Profits=[1,2,3], Capital=[0,1,1].
输出: 4
解释: 由于你的初始资本为 0,你尽可以从 0 号项目开始。 在完成后,你将获得 1 的利润,你的总资本将变为 1。 此时你可以选择开始 1 号或 2 号项目。 由于你最多可以选择两个项目,所以你需要完成 2 号项目以获得最大的资本。 因此,输出最后最大化的资本,为 0 + 1 + 3 = 4。
注意:
假设所有输入数字都是非负整数。 表示利润和资本的数组的长度不超过 50000。 答案保证在 32 位有符号整数范围内。
LeetCode:我疯起来连自己都卖
PS:
利用优先队列来完成, 建立两个优先队列, 一个pqCap按成本升序排列, 一个pqPro按受益高低排列
把所有小于等于W的<成本, 收益>对从pqCap中取出并放入prPro, 只要k大于0就从pqPro中poll一个
加入W, 最后返回W
class Solution {
public int findMaximizedCapital(int k, int W, int[] Profits, int[] Capital) {
if(Profits.length < 1) return W;
PriorityQueue<int[]> pqCap = new PriorityQueue<>((a, b) -> (a[0]-b[0]));
PriorityQueue<int[]> pqPro = new PriorityQueue<>((a, b) -> (b[1]-a[1]));
for(int i = 0; i < Profits.length; ++i)
pqCap.offer(new int[]{Capital[i], Profits[i]});
while(k-- != 0) {
while(!pqCap.isEmpty() && pqCap.peek()[0] <= W)
pqPro.offer(pqCap.poll());
if(pqPro.isEmpty())
break;
W += pqPro.poll()[1];
}
return W;
}
}
503. 下一个更大元素 II
给定一个循环数组(最后一个元素的下一个元素是数组的第一个元素),输出每个元素的下一个更大元素。数字 x 的下一个更大的元素是按数组遍历顺序,这个数字之后的第一个比它更大的数,这意味着你应该循环地搜索它的下一个更大的数。如果不存在,则输出 -1。
示例 1:
输入: [1,2,1] 输出: [2,-1,2] 解释: 第一个 1 的下一个更大的数是 2; 数字 2 找不到下一个更大的数; 第二个 1 的下一个最大的数需要循环搜索,结果也是 2。 注意: 输入数组的长度不会超过 10000。
单调栈
因为是循环数组,我们把数组循环两遍,就可以在本题模拟出类似循环数组的情况
取数组内的值的时候,如果是第二遍循环数组,我们要对 n 取余,才能取到值
栈内放的是下标,
循环栈,看栈内的下标对应的值是不是比当前的值小。如果比当前小,证明当前值就是下标后最大的值
如果是第一遍循环就把下标加入栈,(两遍循环时为了做到循环数组的功能,应对的是,位于数组后方的值的下一个最大的在数组前面)
class Solution {
public int[] nextGreaterElements(int[] nums) {
int n = nums.length;
int [] res = new int[n];
Arrays.fill(res, -1);
Stack <Integer> stack = new Stack<>();
for (int i = 0; i < n*2; i++){
int num = nums[i % n];
while(!stack.isEmpty() && num > nums[stack.peek()]){
res[stack.pop()] = num;
}
if(i < n) stack.add(i);
}
return res;
}
}
504. 七进制数
给定一个整数,将其转化为7进制,并以字符串形式输出。
示例 1:
输入: 100 输出: "202" 示例 2:
输入: -7 输出: "-10" 注意: 输入范围是 [-1e7, 1e7] 。
第一个方法是系统自带的方法
第二个是正常的进制转换,但是这个题的复杂点在于可以是负数
(请忽略digits数组里面那些多余的项)
我们把正数负数都当作负数来处理,等最后的时候如果是负数在做负数处理
每次都是取余,进位,取余,进位
class Solution {
public String convertToBase7(int num) {
return Integer.toString(num, 7);
}
}
class Solution {
final static char[] digits = {
'0' , '1' , '2' , '3' , '4' , '5' ,
'6' , '7' , '8' , '9' , 'a' , 'b' ,
'c' , 'd' , 'e' , 'f' , 'g' , 'h' ,
'i' , 'j' , 'k' , 'l' , 'm' , 'n' ,
'o' , 'p' , 'q' , 'r' , 's' , 't' ,
'u' , 'v' , 'w' , 'x' , 'y' , 'z'
};
public String convertToBase7(int num){
char buf[] = new char[33];
boolean negative = (num < 0);
int charPos = 32;
if (!negative) {
num = -num;
}
while (num <= -7) {
buf[charPos--] = digits[-(num % 7)];
num = num / 7;
}
buf[charPos] = digits[-num];
if (negative) {
buf[--charPos] = '-';
}
return new String(buf, charPos, (33 - charPos));
}
}
506. 相对名次
给出 N 名运动员的成绩,找出他们的相对名次并授予前三名对应的奖牌。前三名运动员将会被分别授予 “金牌”,“银牌” 和“ 铜牌”("Gold Medal", "Silver Medal", "Bronze Medal")。
(注:分数越高的选手,排名越靠前。)
示例 1:
输入: [5, 4, 3, 2, 1] 输出: ["Gold Medal", "Silver Medal", "Bronze Medal", "4", "5"] 解释: 前三名运动员的成绩为前三高的,因此将会分别被授予 “金牌”,“银牌”和“铜牌” ("Gold Medal", "Silver Medal" and "Bronze Medal"). 余下的两名运动员,我们只需要通过他们的成绩计算将其相对名次即可。 提示:
N 是一个正整数并且不会超过 10000。 所有运动员的成绩都不相同。
用计数排序,把成绩计数排序一遍
map[成绩] = 人数
然后进行转换:(按照成绩倒叙循环)
map[成绩] = 名次
然后转换成目标数组,前三名做一下处理
class Solution {
public String[] findRelativeRanks(int[] nums) {
int len = nums.length;
String[] result = new String[len];
if (len<1)return result;
//1、可以把数组转换成键值对(下标:成绩)按成绩排序,最后取出对应名次
//2、分数总量不大,不超过10000,可以用计数排序
int min = 0;
for (int num : nums) {
min = num>min?num:min;
}
int[] map = new int[min+1];
for (int num : nums) {
map[num]++;
}
//把map中每个分数对应的人数,转换成对应名次
int rank = 1;int temp = 0;
for (int i = min; i >= 0; i--) {
if (map[i]!=0){
temp = map[i];
map[i] = rank;
rank += temp;
}
}
//把名次映射成金银铜奖"Gold Medal", "Silver Medal", "Bronze Medal"
String s = "";int value = 0;
for (int i = 0; i < len; i++) {
value= map[nums[i]];
switch (value){
case 1: s = "Gold Medal";break;
case 2: s = "Silver Medal";break;
case 3: s = "Bronze Medal";break;
default: s = String.valueOf(value);
}
result[i] = s;
}
return result;
}
}
507. 完美数
对于一个 正整数,如果它和除了它自身以外的所有正因子之和相等,我们称它为“完美数”。
给定一个 整数 n, 如果他是完美数,返回 True,否则返回 False
示例:
输入: 28 输出: True 解释: 28 = 1 + 2 + 4 + 7 + 14
提示:
输入的数字 n 不会超过 100,000,000. (1e8)
完全数:
奇数不能是完全数
找因子只需要找到目标数的开方就可以
class Solution {
public boolean checkPerfectNumber(int num) {
if (num % 2 != 0)
return false;
int count = 0;
for (int i = 2; i * i < num; i++)
count += num % i == 0 ? i + num / i : 0;
return count + 1 == num;
}
}
508. 出现次数最多的子树元素和
给出二叉树的根,找出出现次数最多的子树元素和。一个结点的子树元素和定义为以该结点为根的二叉树上所有结点的元素之和(包括结点本身)。然后求出出现次数最多的子树元素和。如果有多个元素出现的次数相同,返回所有出现次数最多的元素(不限顺序)。
示例 1 输入:
5
/ \
2 -3
返回 [2, -3, 4],所有的值均只出现一次,以任意顺序返回所有值。
示例 2 输入:
5
/ \
2 -5
返回 [2],只有 2 出现两次,-5 只出现 1 次。
提示: 假设任意子树元素和均可以用 32 位有符号整数表示。
遍历树就正常遍历:
每次遍历到一个结点,左右结点都遍历后,把左右节点的值加上当前结点的值为当前子树的结点和
用map保存一下每个子树的元素和,键存结点和,值存当前结点和相同的子树数量,记录一下最多的子树数量
输出的时候直接循环map,把出现次数最多的子树元素和放入list返回
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
private int max = 0;
public int[] findFrequentTreeSum(TreeNode root) {
if(root == null) return new int[0];
Map<Integer,Integer> map = new HashMap<>();
helper(root,map);
//然后求出map中value最大值对应的Key
List<Integer> res = new LinkedList<>();
for(Integer i : map.keySet()){
if(map.get(i) == max)
res.add(i);
}
int[] resArr = new int[res.size()];
for(int i = 0;i < res.size();i++){
resArr[i] = res.get(i);
}
return resArr;
}
private int helper(TreeNode root,Map<Integer,Integer> map){
if(root == null) return 0;
//求出当前节点为根的元素和
int left = helper(root.left,map);
int right = helper(root.right,map);
int val = left+right+root.val;
map.put(val,map.getOrDefault(val,0)+1);
max = Math.max(max,map.get(val));
return val;
}
}
509. 斐波那契数
斐波那契数,通常用 F(n) 表示,形成的序列称为斐波那契数列。该数列由 0 和 1 开始,后面的每一项数字都是前面两项数字的和。也就是:
F(0) = 0, F(1) = 1 F(N) = F(N - 1) + F(N - 2), 其中 N > 1. 给定 N,计算 F(N)。
示例 1:
输入:2 输出:1 解释:F(2) = F(1) + F(0) = 1 + 0 = 1. 示例 2:
输入:3 输出:2 解释:F(3) = F(2) + F(1) = 1 + 1 = 2. 示例 3:
输入:4 输出:3 解释:F(4) = F(3) + F(2) = 2 + 1 = 3.
提示:
0 ≤ N ≤ 30
PS:
第一个比较简单,
第二个是用黄金分割求斐波那契
第三个是矩阵求斐波那契
class Solution {
public int fib(int N) {
// if (N == 0 || N == 1) {
// return N;
// }
// int x = 0,y = 1,z = 1,i = 0,end = N-2;
// while (i <= end) {
// z = x + y;
// x = y;
// y = z;
// i++;
// }
// return z;
// double goldenRatio = (1 + Math.sqrt(5)) / 2;
// return (int)Math.round(Math.pow(goldenRatio, N)/ Math.sqrt(5));
if (N <= 1) {
return N;
}
int[][] A = new int[][]{{1, 1}, {1, 0}};
matrixPower(A, N-1);
return A[0][0];
}
void matrixPower(int[][] A, int N) {
if (N <= 1) {
return;
}
matrixPower(A, N/2);
multiply(A, A);
int[][] B = new int[][]{{1, 1}, {1, 0}};
if (N%2 != 0) {
multiply(A, B);
}
}
void multiply(int[][] A, int[][] B) {
int x = A[0][0] * B[0][0] + A[0][1] * B[1][0];
int y = A[0][0] * B[0][1] + A[0][1] * B[1][1];
int z = A[1][0] * B[0][0] + A[1][1] * B[1][0];
int w = A[1][0] * B[0][1] + A[1][1] * B[1][1];
A[0][0] = x;
A[0][1] = y;
A[1][0] = z;
A[1][1] = w;
}
}