需要开通vip的题目暂时跳过
点击链接可跳转到所有刷题笔记的导航链接
假设 力扣(LeetCode)即将开始其 IPO。为了以更高的价格将股票卖给风险投资公司,力扣 希望在 IPO 之前开展一些项目以增加其资本。 由于资源有限,它只能在 IPO 之前完成最多 k 个不同的项目。帮助 力扣 设计完成最多 k 个不同项目后得到最大总资本的方式。
给定若干个项目。对于每个项目 i,它都有一个纯利润 Pi,并且需要最小的资本 Ci 来启动相应的项目。最初,你有 W 资本。当你完成一个项目时,你将获得纯利润,且利润将被添加到你的总资本中。
总而言之,从给定项目中选择最多 k 个不同项目的列表,以最大化最终资本,并输出最终可获得的最多资本。
解答
public int findMaximizedCapital(int k, int W, int[] Profits, int[] Capital) {
PriorityQueue<PC> queue = new PriorityQueue<>(new Comparator<PC>(){
public int compare(PC p1,PC p2){
return p2.profit - p1.profit;
}
});
for(int i = 0;i < Profits.length;i++){
queue.add(new PC(Profits[i],Capital[i]));
}
while(k > 0 && !queue.isEmpty()){
List<PC> list = new ArrayList<>();
boolean flag = false;
while(!queue.isEmpty()){
PC pc = queue.poll();
if(pc.capital <= W){
W += pc.profit;
k--;
flag = true;
break;
}
list.add(pc);
}
if(flag)
queue.addAll(list);
}
return W;
}
public class PC{
int profit;
int capital;
public PC(int profit,int capital){
this.profit = profit;
this.capital = capital;
}
}
分析
给定一个循环数组(最后一个元素的下一个元素是数组的第一个元素),输出每个元素的下一个更大元素。数字 x 的下一个更大的元素是按数组遍历顺序,这个数字之后的第一个比它更大的数,这意味着你应该循环地搜索它的下一个更大的数。如果不存在,则输出 -1。
解答
//方法1
public int[] nextGreaterElements(int[] nums) {
int len = nums.length;
int[] res = new int[len];
int max = Integer.MIN_VALUE;
for(int i = 0;i < len;i++){
max = Math.max(max,nums[i]);
}
for(int i = 0;i < len;i++){
if(nums[i] == max){
res[i] = -1;
continue;
}
for(int j = i + 1;j < i + len;j++){
int temp = j;
if(j >= len){
temp -= len;
}
if(nums[temp] > nums[i]){
res[i] = nums[temp];
break;
}
}
}
return res;
}
//方法2
public int[] nextGreaterElements(int[] nums) {
int[] res = new int[nums.length];
Stack<Integer> stack = new Stack<>();
for (int i = 2 * nums.length - 1; i >= 0; --i) {
while (!stack.empty() && nums[stack.peek()] <= nums[i % nums.length]) {
stack.pop();
}
res[i % nums.length] = stack.empty() ? -1 : nums[stack.peek()];
stack.push(i % nums.length);
}
return res;
}
分析
提交结果
给定一个整数,将其转化为7进制,并以字符串形式输出。
解答
public String convertToBase7(int num) {
if(num == 0) return "0";
StringBuilder sb = new StringBuilder();
boolean pos = num >= 0;
num = Math.abs(num);
while(num != 0) {
sb.append(num % 7);
num = num / 7;
}
if(!pos) {
sb.append('-');
}
return sb.reverse().toString();
}
分析
给出 N 名运动员的成绩,找出他们的相对名次并授予前三名对应的奖牌。前三名运动员将会被分别授予 “金牌”,“银牌” 和“ 铜牌”(“Gold Medal”, “Silver Medal”, “Bronze Medal”)。
(注:分数越高的选手,排名越靠前。)
解答
public String[] findRelativeRanks(int[] nums) {
String[] res = new String[nums.length];
String[] medals = new String[]{"Gold Medal", "Silver Medal", "Bronze Medal"};
int index = 1;
PriorityQueue<A> queue = new PriorityQueue<>(new Comparator<A>(){
public int compare(A a1,A a2){
return a2.score - a1.score;
}
});
for(int i = 0;i < nums.length;i++){
queue.add(new A(nums[i],i));
}
while(!queue.isEmpty()){
A cur = queue.poll();
if(index <= 3){
res[cur.index] = medals[index-1];
}else{
res[cur.index] = ""+index;
}
index++;
}
return res;
}
class A{
int score;
int index;
public A(int score,int index){
this.score = score;
this.index = index;
}
}
分析
对于一个 正整数,如果它和除了它自身以外的所有 正因子 之和相等,我们称它为 「完美数」。
给定一个 整数 n, 如果是完美数,返回 true,否则返回 false
解答
//方法1
public boolean checkPerfectNumber(int num) {
if (num <= 0) {
return false;
}
int sum = 0;
for (int i = 1; i * i <= num; i++) {
if (num % i == 0) {
sum += i;
if (i * i != num) {
sum += num / i;
}
}
}
return sum - num == num;
}
//方法2
public int pn(int p) {
return (1 << (p - 1)) * ((1 << p) - 1);
}
public boolean checkPerfectNumber(int num) {
int[] primes=new int[]{2,3,5,7,13,17,19,31};
for (int prime: primes) {
if (pn(prime) == num)
return true;
}
return false;
}
分析
提交结果
解答
Map<Integer,Integer> map = new HashMap<>();
public int[] findFrequentTreeSum(TreeNode root) {
if(root == null)return new int[0];
dfs(root);
dfs2(root);
Map<Integer, List<Integer>> map2 = new HashMap<>();
for (int key : map.keySet()) {
int number = map.get(key);
List<Integer> list = map2.getOrDefault(number, new ArrayList<>());
list.add(key);
map2.put(number, list);
}
int targetKey = 0;
for (int key : map2.keySet()) {
if (key > targetKey) {
targetKey = key;
}
}
List<Integer> list = map2.get(targetKey);
int[] res = new int[list.size()];
for (int i = 0; i < list.size(); i++) {
res[i] = list.get(i);
}
return res;
}
public int dfs(TreeNode root){
if(root.left !=null){
root.val += dfs(root.left);
}
if(root.right != null){
root.val += dfs(root.right);
}
return root.val;
}
public void dfs2(TreeNode root){
map.put(root.val,map.getOrDefault(root.val,0) + 1);
if(root.left !=null) dfs2(root.left);
if(root.right !=null) dfs2(root.right);
}
分析
解答
public int fib(int N) {
if(N <= 1)return N;
int first = 0;
int second = 1;
int res = 0;
for(int i = N;i > 1;i--){
res = first + second;
first = second;
second = res;
}
return res;
}
分析
视频游戏“辐射4”中,任务“通向自由”要求玩家到达名为“Freedom Trail Ring”的金属表盘,并使用表盘拼写特定关键词才能开门。
给定一个字符串 ring,表示刻在外环上的编码;给定另一个字符串 key,表示需要拼写的关键词。您需要算出能够拼写关键词中所有字符的最少步数。
最初,ring 的第一个字符与12:00方向对齐。您需要顺时针或逆时针旋转 ring 以使 key 的一个字符在 12:00 方向对齐,然后按下中心按钮,以此逐个拼写完 key 中的所有字符。
旋转 ring 拼出 key 字符 key[i] 的阶段中:
解答
public int findRotateSteps(String ring, String key) {
int n = ring.length(), m = key.length();
List<Integer>[] pos = new List[26];
for (int i = 0; i < 26; ++i) {
pos[i] = new ArrayList<Integer>();
}
for (int i = 0; i < n; ++i) {
pos[ring.charAt(i) - 'a'].add(i);
}
int[][] dp = new int[m][n];
for (int i = 0; i < m; ++i) {
Arrays.fill(dp[i], 0x3f3f3f);
}
for (int i : pos[key.charAt(0) - 'a']) {
dp[0][i] = Math.min(i, n - i) + 1;
}
for (int i = 1; i < m; ++i) {
for (int j : pos[key.charAt(i) - 'a']) {
for (int k : pos[key.charAt(i - 1) - 'a']) {
dp[i][j] = Math.min(dp[i][j], dp[i - 1][k] + Math.min(Math.abs(j - k), n - Math.abs(j - k)) + 1);
}
}
}
int[] last = dp[m - 1];
int res = Integer.MAX_VALUE;
for(int i = 0;i < last.length;i++){
res = Math.min(last[i],res);
}
return res;
}
分析
记录下字符串key 中每一个字符,在ring中出现的位置。记为pos
动态规划 dp[i] [j]表示 key中的第i个字符,ring中第j个字符在12点钟方向 上相等的最小步数。
初始化dp[0] [j] 就是从pos[key.charAt(0) - ‘a’] 中找一个最小的值 + 1.即为key第一个字符 在 ring中第j个字符 匹配的最小步数。
从key的下一个字符开始遍历。
第二层循环 遍历当前字符在ring中出现的位置。
第三层循环 表示上一个字符匹配的位置。
所以动态转移方程可以写为
dp[i] [j] = Math.min(dp[i] [j],dp[i - 1] [k] + Math.min(Math.abs(j-k),n - Math.abs(j - k)) + 1);
表示上一个位置 到j的最小距离 再 加1步拼写步骤。
您需要在二叉树的每一行中找到最大的值。
解答
public List<Integer> largestValues(TreeNode root) {
List<Integer> res = new ArrayList<>();
if(root == null)return res;
LinkedList<TreeNode> queue = new LinkedList<>();
queue.addLast(root);
while(!queue.isEmpty()){
LinkedList<TreeNode> temp = new LinkedList<>();
int max = Integer.MIN_VALUE;
while(!queue.isEmpty()){
TreeNode cur = queue.removeFirst();
max = Math.max(cur.val,max);
if(cur.left!=null)temp.addLast(cur.left);
if(cur.right!=null)temp.addLast(cur.right);
}
res.add(max);
queue = temp;
}
return res;
}
分析
给定一个字符串 s ,找到其中最长的回文子序列,并返回该序列的长度。可以假设 s 的最大长度为 1000 。
解答
public int longestPalindromeSubseq(String s) {
int n = s.length();
int[][] dp = new int[n][n];
for(int i = n - 1;i >=0 ;i--){
dp[i][i] = 1;
for(int j = i + 1;j < n;j++){
if(s.charAt(i) == s.charAt(j)){
dp[i][j] = dp[i+1][j-1] + 2;
}else{
dp[i][j] = Math.max(dp[i+1][j],dp[i][j-1]);
}
}
}
return dp[0][n-1];
}
分析
dp[i] [j]表示 i到j的最长回文子序列。
i从后往前遍历,j从i+1往后遍历。这样就可以求得所有的子问题。
初始化dp[i] [i] = 1
动态转移方程,当i和j对应的字符相同的时候
dp[i] [j] = dp[i+1] [j-1] + 2;
否则 取他们子问题的最大值
即 dp[i] [j] = Math.max(dp[i+1] [j],dp[i] [j-1])
最后返回dp[0] [n-1]即为答案。
假设有 n 台超级洗衣机放在同一排上。开始的时候,每台洗衣机内可能有一定量的衣服,也可能是空的。
在每一步操作中,你可以选择任意 m (1 ≤ m ≤ n) 台洗衣机,与此同时将每台洗衣机的一件衣服送到相邻的一台洗衣机。
给定一个非负整数数组代表从左至右每台洗衣机中的衣物数量,请给出能让所有洗衣机中剩下的衣物的数量相等的最少的操作步数。如果不能使每台洗衣机中衣物的数量相等,则返回 -1。
解答
public int findMinMoves(int[] machines) {
int res = Integer.MIN_VALUE;
int sum = 0;
for(int i = 0;i < machines.length;i++){
sum += machines[i];
}
if(sum % machines.length != 0)return -1;
int main = sum / machines.length;
for(int i = 0;i < machines.length;i++){
machines[i] -= main;
}
int preSum = 0;
int max = Integer.MIN_VALUE;
int preSumMax = Integer.MIN_VALUE;
for(int i = 0;i < machines.length;i++){
preSum += machines[i];
preSumMax = Math.max(preSumMax,Math.abs(preSum));
max = Math.max(max,machines[i]);
res = Math.max(preSumMax,max);
}
return res;
}
分析
给定不同面额的硬币和一个总金额。写出函数来计算可以凑成总金额的硬币组合数。假设每一种面额的硬币有无限个。
解答
public int change(int amount, int[] coins) {
int k = coins.length+1;
int[][] dp = new int[k + 1][amount + 1];
for(int i = 0;i <= k;i++){
dp[i][0] = 1;
}
for(int i = 1;i <= amount;i++){
for(int j = 1;j < k;j++){
if(i >= coins[j-1]){
dp[j][i] = dp[j-1][i] + dp[j][i - coins[j-1]];
}else{
dp[j][i] = dp[j-1][i];
}
}
}
return dp[k-1][amount];
}
分析
dp[j] [i]表示前j个硬币 得到i金额的组合数。
初始化dp[i] [0] = 1;前i个硬币得到金额0的组合数为1
动态转移方程
当前金额大于当前遍历的硬币金额
dp[j] [i] = dp[j-1] [i] + dp[j] [i-coins[j-1]];
表示前j个硬币得到i金额的组合数量。= 前j-1个硬币得到i金额的组合数量 + 前j个硬币得到i-coins[j-1]的金额的组合数量。
题中给出一个 n_rows 行 n_cols 列的二维矩阵,且所有值被初始化为 0。要求编写一个 flip 函数,均匀随机的将矩阵中的 0 变为 1,并返回该值的位置下标 [row_id,col_id];同样编写一个 reset 函数,将所有的值都重新置为 0。尽量最少调用随机函数 Math.random(),并且优化时间和空间复杂度。
解答
class Solution {
Map<Integer, Integer> V = new HashMap<>();
int nr, nc, rem;
Random rand = new Random();
public Solution(int n_rows, int n_cols) {
nr = n_rows;
nc = n_cols;
rem = nr * nc;
}
public int[] flip() {
int r = rand.nextInt(rem--);
int x = V.getOrDefault(r, r);
V.put(r, V.getOrDefault(rem, rem));
return new int[]{x / nc, x % nc};
}
public void reset() {
V.clear();
rem = nr * nc;
}
}
分析
给定一个单词,你需要判断单词的大写使用是否正确。
我们定义,在以下情况时,单词的大写用法是正确的:
否则,我们定义这个单词没有正确使用大写字母。
解答
public boolean detectCapitalUse(String word) {
boolean flagFirst = false;
int number = 0;
for(int i = 0;i < word.length();i++){
char cur = word.charAt(i);
if(cur >= 'A' && cur <= 'Z'){
if(i == 0) flagFirst = true;
number++;
}
}
return (flagFirst && number == 1) || number == word.length() || number == 0;
}
分析