牛客刷题记录(常见笔试题)
创始人
2024-02-01 09:02:19
0

目录

一、Map的应用篇

乒 乓球筐

简单的错误记录

二、动态规划篇

计算字符串的编辑距离

年终奖

最长不含重复字符的子字符串

合唱团

三、数组篇

顺时针打印矩阵


一、Map的应用篇

乒 乓球筐

题目地址:乒乓球筐

小白代码

import java.util.*;// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {public static void main(String[] args) {Scanner in = new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNext()) { // 注意 while 处理多个 caseString A = in.next();String B = in.next();Map map = new HashMap<>();for (int i = 0; i < A.length(); ++i) {if (!map.containsKey(A.charAt(i))) {map.put(A.charAt(i), 1);}else {int temp = map.get(A.charAt(i));map.put(A.charAt(i), temp + 1);}}int[] arrB = new int[100];for (int i = 0; i < B.length(); ++i) {// System.out.println(B.charAt(i) - 'A');arrB[B.charAt(i) - 'A']++;}int flag = 1;for (int i = 0; i < B.length(); ++i) {if (map.containsKey(B.charAt(i))) {int j = B.charAt(i) - 'A';if (arrB[j] <= map.get(B.charAt(i))) {// 符合要求什么也不做}else {// 不符合要求就改变flagflag = 0;}}else {flag = 0;}}if (flag == 1) {System.out.println("Yes");}else {System.out.println("No");}}}
}

扩展做法

// write your code here
// write your code here
import java.util.*;// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {public static void main(String[] args) {Scanner in = new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNext()) { // 注意 while 处理多个 caseString temp = in.next();StringBuilder A = new StringBuilder(temp);String B = in.next();char[] find = B.toCharArray();int flag = 1;for (char ch : find) {// 不等于-1,说明该字符在A中int index = A.indexOf(String.valueOf(ch));if (index != -1) {// 题目要求的是B中的字符在A中都有,并且在B中的数量不多于在A中的数量// 我们就在遍历B中的过程,逐步的删除A中与B中相同的字符,如果从头到尾B中的字符都在A中// 删除就是防止A中虽然有B中的字符,但没有B中的字符数量多A.deleteCharAt(index); }else {flag = 0;}}if (flag == 1) {System.out.println("Yes");}else {System.out.println("No");}}}
}

简单的错误记录

简单的错误记录

 

思路:

将每一个数据都存入到HashMap中,最后输出的时候只输出8个即可

代码如下

import java.io.IOException;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Scanner;
import java.io.*;public class Main {public static void main(String[] args) throws IOException {BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));HashMap map = new LinkedHashMap();String str = null;while ((str = bf.readLine()) != null) {String[] strs = str.split(" ");String[] split = strs[0].split("\\\\");  //根据\分割int LineNum = Integer.parseInt(strs[1]);String FileName = split[split.length - 1];//只保留最后16位if (FileName.length() > 16)FileName = FileName.substring(FileName.length() - 16);String key = FileName + " " + LineNum;//放入到HashMap中int Number = 1;if (map.containsKey(key))map.put(key, map.get(key) + 1);else {map.put(key, Number);}}int count = 0;for (String string : map.keySet()) {count++;if (count > (map.keySet().size() - 8)) //输出最后八个记录System.out.println(string + " " + map.get(string));}}
}

二、动态规划篇

计算字符串的编辑距离

计算字符串的编辑距离

import java.io.*; // BufferedReader需要用
import java.util.*;
// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {public static void main(String[] args) throws IOException{BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));String strA = null;// 注意 hasNext 和 hasNextLine 的区别while ((strA = bf.readLine()) != null) {String strB = bf.readLine();// f[i][j]表示把A字符串的前i个字符转换成字符串B的前j个字符,需要进行的编辑距离int lenA = strA.length();int lenB = strB.length();int[][] ret = new int[lenA + 1][lenB + 1];ret[0][0] = 0;for (int i = 0; i <= lenA; ++i) {ret[i][0] = i;}for (int j = 0; j <= lenB; ++j) {ret[0][j] = j;}// 状态转移方程:ret[i][j] = ret[i][j - 1] + 1 || ret[i][j] = ret[i - 1][j] + 1;/// ret[i][j] = ret[i - 1][j - 1] + 1;for (int i = 1; i <= lenA; ++i) {for (int j = 1; j <= lenB; ++j) {// 这里有些特殊,因为我们的字符真正的数据是从0,下标开始的——》即0下标和我们的ret[1][1]对应// 但我们这个ret[0][0]if (strA.charAt(i - 1) == strB.charAt(j - 1)) { // 说明我们字符串A的第一个字符和我们字符串B的第一个字符相同ret[1][1] = 0;ret[i][j] = ret[i - 1][j - 1];}else {ret[i][j] = Math.min(Math.min(ret[i - 1][j], ret[i][j - 1]), ret[i - 1][j - 1]) + 1;}}}System.out.println(ret[lenA][lenB]);}}
}

年终奖

题目链接:年终奖

import java.util.*;/**
这个计算过程中有三个特殊情况情况1:如果是起点,那么直接忽略即可
情况2:如果处在第一行,那么由于是第一行,所以从起点走,它只可能是向右不断走得到的
情况3:如果处在第一列,那么由于是第一列,所以从起点走,它只可能是向下不断走的到的*/
public class Bonus {// 建立一个相同的矩阵board,board[i][j]表示从起点到i,j这一点中某条路径代表的礼物价值值总和// 但要注意我们这里一开始传的参数board只是表示这一点的礼物价值,还不是到达这一点的路径总价值——》是经过不断构建才形成的礼物价值总和数组board[i][j];public int getMost(int[][] board) {// write code hereint row = board.length; // 行数int col = board[0].length;// 每一行有多少列// 先要把borad[0][j]第一行、board[i][0]第一列给构建好了,使得borad[i][0]、board[0][j]就代表从起点到这一列这个位置或者这一行这个位置的所获得的礼物总价值for (int i = 1; i < row; ++i) {board[i][0] = board[i - 1][0] + board[i][0];}for (int j = 1; j < col; ++j) {board[0][j] = board[0][j - 1] + board[0][j];}// 此时,第一行borad[i][0]、board[0][j]就代表从起点到这一列或者这一行的总价值// 接下来我们要构建中间的了(在第一行和第一列的基础上)for (int i = 1; i < row; ++i) {for (int j = 1; j < col; ++j) {// 对于这样一个棋盘,到达(i,j)这一点要么是上一行(i-1,j)向下移动一行得到,要么是前一列(i,j-1)向右移动一列得到board[i][j] = Math.max(board[i - 1][j], board[i][j - 1]) + board[i][j];  // board[i][j]代表了此时从起点到board[i][j]位置所经过路径所获得的礼物总价值}}return board[row - 1][col - 1];}
}

如果你对上面的board[i][j]代表的究竟是这一点的礼物价值,还是从起点到这一点所经过的路径的总价值不太清楚的话。

我们不妨另外构建一个矩阵gifts[i][j]来专门表示从起点到i,j这一点中某条路径代表的礼物价值值总和。

 思路分析:

 这道题属于贪心算法,但本质仍然是动态规划。对于这样一个棋盘,到达(i,j)这一点要么是上一行(i-1,j)向下移动一行得到,要么是前一列(i,j-1)向右移动一列得到

这个计算过程中有三个特殊情况

  • 情况1:如果是起点,那么直接忽略即可
  • 情况2:如果处在第一行,那么由于是第一行,所以从起点走,它只可能是向右不断走得到的
  • 情况3:如果处在第一列,那么由于是第一列,所以从起点走,它只可能是向下不断走的到的

其余情况均是即可向右走,也可以向下走

代码:

import java.util.*;public class Bonus {public int getMost(int[][] board) {// write code hereint row = board.length;int col = board[0].length;// gifts[i][j]表示从起点到i,j这一点中某条路径代表的礼物价值值总和int[][] gifts = new int[row][col];gifts[0][0] = board[0][0];for (int i = 1; i < row; ++i) {gifts[i][0] = gifts[i - 1][0] + board[i][0];}for (int j = 1; j < col; ++j) {gifts[0][j] = gifts[0][j - 1] + board[0][j];}for (int i = 1; i < row; ++i) {for (int j = 1; j < col; ++j) {// 对于这样一个棋盘,到达(i,j)这一点要么是上一行(i-1,j)向下移动一行得到,要么是前一列(i,j-1)向右移动一列得到gifts[i][j] = Math.max(gifts[i - 1][j], gifts[i][j - 1]) + board[i][j];  // board[i][j]代表此点上的礼物价值// gifts[i][j]代表从起点到i,j这一点所经过路径代表的礼物价值总和}}return gifts[row - 1][col - 1];}
}

最长不含重复字符的子字符串

  • step 1:dp[i]dp[i]dp[i]表示以下标i结尾的字符串最长不含重复子串的长度,用哈希表记录是否重复出现字符,并记录其下标位置。
  • step 2:遍历字符串,哈希表中没有出现过的就不是重复,因此考虑dp[i]=dp[i−1]+1,即在前一个字符的基础上加上它。
  • step 3:哈希表中出现过的,这是重复的字符,考虑i−map[s[i]],但是为了防止中间出现其他重复的字符,还是应该考虑它的前一个字符的基础,因此实际转移方程为dp[i]=min(dp[i−1]+1,i−map[s[i−1]])——map[s[i - 1]]
  • step 4:遍历过程中遇到的字符都要加入哈希表,同时维护最大的长度。
import java.util.*;public class Solution {/*** 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可** * @param s string字符串 * @return int整型*/public int lengthOfLongestSubstring (String str) {// write code hereint[] dp= new int[str.length()];char[] s = str.toCharArray(); dp[0] = 1; // dp[i]代表以s[i]结尾的的字符串的最长子字符串的长度Map map = new HashMap<>();map.put(str.charAt(0), 0);int res = 1, len = 0; // 当字符串只有一个字符,程序不会执行for循环,此时要进行特判for (int i = 1; i < str.length(); ++i) {if (!map.containsKey(str.charAt(i))) {dp[i] = dp[i - 1] + 1;}else {dp[i] = Math.min(dp[i - 1] + 1, i - map.get(str.charAt(i)));// dp[i] = i - map.get(str.charAt(i));}map.put(str.charAt(i), i);res = Math.max(dp[i], res);}return res;}
}

合唱团

牛客链接

import java.util.*;
import java.io.*;
public class Main {public static void main(String[] args) throws IOException{BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));String str = null;while((str = bf.readLine()) != null) {int n = Integer.parseInt(str);String num = bf.readLine();String[] nums = num.split(" ");int[] a = new int[nums.length];for (int i = 0; i < nums.length; ++i) {a[i] = Integer.parseInt(nums[i]);}String str2 = bf.readLine();String[] strs2 = str2.split(" ");int k = Integer.parseInt(strs2[0]);int d = Integer.parseInt(strs2[1]);long[][] maxVal = new long[n + 1][k + 1];long[][] minVal = new long[n + 1][k + 1];// maxVal[i][j]代表当最后一个是第i个同学,共选了j个同学所得到了最大能力值// 初始化for (int i = 1; i <= n; ++i) {maxVal[i][1] = minVal[i][1] = a[i - 1];}long ret = 0;for (int i = 1; i <= n; ++i) {for (int j = 1; j <= k; ++j) {// 约束条件for (int m = i - 1; m >= Math.max(i - d, 1); --m) {maxVal[i][j] = Math.max(maxVal[i][j], Math.max(maxVal[m][j - 1] * a[i - 1], minVal[m][j - 1] * a[i - 1]));minVal[i][j] = Math.min(minVal[i][j], Math.min(minVal[m][j - 1] * a[i - 1], maxVal[m][j - 1] * a[i - 1]));}}ret = Math.max(ret, maxVal[i][k]);}System.out.println(ret);}}   
}

三、数组篇

顺时针打印矩阵

解题思路

1、声明四个变量,分别为左界限 L,右界限 R,上界限 T,下界限 B。

2、先从左往右遍历,然后从上到下,从右往左,最后从下往上。循环这个操作,每次从左往右遍历完,T += 1,说明最上面这一行已经遍历过了,上界限 T 应该往下移了;从上往下遍历完, R -= 1,说明最右边这一列已经遍历过了,右界限 R 应该往左移了;其他遍历操作也是如此。当四个界限中,T 和 B,或者 L 和 R 碰撞在一起,说明遍历完成,退出循环。

3、值得注意的是,需要考虑非方阵的情况,比如矩阵 A[3][4],因为行数比列数少,T 和 B 碰撞时 L 和 R 仍未碰撞,若此时还在循环体内,会继续执行遍历操作。所以在循环体内,需要时刻监控界限碰撞的情况。

 

 

 

 

import java.util.ArrayList;
public class Solution {public ArrayList printMatrix(int [][] matrix) {int t = 0;int b = matrix.length - 1, row = matrix.length;int l = 0;int r = matrix[0].length - 1, col = matrix[0].length;ArrayList list = new ArrayList<>();while (t <= b && l <= r) {// 从左到右, 需要注意我们的边界都是动态变化的for (int i = l; i <= r; ++i) {list.add(matrix[t][i]);}++t; // 第一行遍历完了,上边界要发生变化if (t > b || l > r) break;// 从上到下for (int j = t; j <= b; ++j) {list.add(matrix[j][r]);}--r;if (t > b || l > r) break;// 从右到左for (int i = r; i >= l; --i) {list.add(matrix[b][i]);}--b;if (t > b || l > r) break;// 从下到上for (int j = b; j >= t; --j) {list.add(matrix[j][l]);}++l;}return list;}
}

相关内容

热门资讯

喜欢穿一身黑的男生性格(喜欢穿... 今天百科达人给各位分享喜欢穿一身黑的男生性格的知识,其中也会对喜欢穿一身黑衣服的男人人好相处吗进行解...
发春是什么意思(思春和发春是什... 本篇文章极速百科给大家谈谈发春是什么意思,以及思春和发春是什么意思对应的知识点,希望对各位有所帮助,...
网络用语zl是什么意思(zl是... 今天给各位分享网络用语zl是什么意思的知识,其中也会对zl是啥意思是什么网络用语进行解释,如果能碰巧...
为什么酷狗音乐自己唱的歌不能下... 本篇文章极速百科小编给大家谈谈为什么酷狗音乐自己唱的歌不能下载到本地?,以及为什么酷狗下载的歌曲不是...
华为下载未安装的文件去哪找(华... 今天百科达人给各位分享华为下载未安装的文件去哪找的知识,其中也会对华为下载未安装的文件去哪找到进行解...
怎么往应用助手里添加应用(应用... 今天百科达人给各位分享怎么往应用助手里添加应用的知识,其中也会对应用助手怎么添加微信进行解释,如果能...
家里可以做假山养金鱼吗(假山能... 今天百科达人给各位分享家里可以做假山养金鱼吗的知识,其中也会对假山能放鱼缸里吗进行解释,如果能碰巧解...
四分五裂是什么生肖什么动物(四... 本篇文章极速百科小编给大家谈谈四分五裂是什么生肖什么动物,以及四分五裂打一生肖是什么对应的知识点,希...
一帆风顺二龙腾飞三阳开泰祝福语... 本篇文章极速百科给大家谈谈一帆风顺二龙腾飞三阳开泰祝福语,以及一帆风顺二龙腾飞三阳开泰祝福语结婚对应...
美团联名卡审核成功待激活(美团... 今天百科达人给各位分享美团联名卡审核成功待激活的知识,其中也会对美团联名卡审核未通过进行解释,如果能...