链接:https://www.nowcoder.com/questionTerminal/29d1622d47514670a85e98a1f47b8e2d
来源:牛客网
已知一种新的火星文的单词由英文字母(仅小写字母)组成,但是此火星文中的字母先后顺序未知。给出一组非空的火星文单词,且此组单词已经按火星文字典序进行好了排序(从小到大),请推断出此火星文中的字母先后顺序。
链接:https://www.nowcoder.com/questionTerminal/29d1622d47514670a85e98a1f47b8e2d
来源:牛客网
输入描述:
一行文本,为一组按火星文字典序排序好的单词(单词两端无引号),单词之间通过空格隔开
输出描述:
按火星文字母顺序输出出现过的字母,字母之间无其他字符,如果无法确定顺序或者无合理的字母排序可能,请输出"invalid"(无需引号)
示例一
输入
z x
输出
zx
示例2
输入
wrt wrf er ett rftt
输出
wertf
示例3
输入
z x z
输出
invalid
我每次做笔试题,看到题目长就可能静不下心去看题,其实和做数学题一样,题目越长越要静下心来分析,挖掘关系
这道题的题目让求火星文中的先后顺序;
顺序由已知的字符串来决定;
具体规则:给出的字符串按从小到大排序;
此时我们根据示例求解;
z x
因为z写在了x前面;所以输出为zx
wrt wrf er ett rftt
这道题大家可能有些疑惑,rftt不是将f写在了t前面,那顺序是不是werft呢,但是答案是wertf
我们仔细思量一下,题目中说的是此组单词按照火星文字典序进行了排序,记住,是此组,不是每一个字母中的每一个字符都按照大小排序,它保证的是前一个字符总体小于后一个字符,可以把第一个字符看成一级比较,二级,三级……一次类推,首先第一个字符进行大小比较再进行第二个字符比较,根据题目中wrt 和 wrf 可以发现,t在f的后面,因为e在r的前面,所以后两个字符的顺序已经确定,而倒推法,加入f在t的前面,那么前两个字符串因为前两个字符相同,那么会wrf wrt这样排序,势必和原题相反,所以,我们比较的根据是前一个和后一个字符的第一个不同的字符来排序
public class IsSort {
//用map记录图,因为有26个字符,直接用二维数组可以表示横纵坐标(两个字符)之间的关系,
private static int[][]map=new int[26][26];
//用来记录当前字符是否是图中的,图中有且未被选为1,已被选即为0
private static int[]indegree=new int[26];
//标记数组,标记字符是否在图中出现
private static boolean[]flag=new boolean[26];
//set集合用来加入字符,统计字符个数,好处是去重
private static Set<Character> set=new HashSet<>();
//结果集
private static List<Character> ans=new ArrayList<>();
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
String[]input=sc.nextLine().split(" ");//生成数组
//int maxLen=0;
//创建图
build(input);
//进行排序
topolpgy();
if(ans.size()==set.size()){
for(Character c:ans){
System.out.print(c);
}
}else {
System.out.println("invalid");
}
}
private static void build(String[] strs) {
String pre=strs[0];//将前一个字符保存
for(char c:pre.toCharArray()){
set.add(c);//加入set集合
}
for(int i=1;i<strs.length;i++){
String cur=strs[i];//将当前字符记录
for(char c:cur.toCharArray()){
set.add(c);//将不同字符加入
}
//循环比较第一个不同的元素,并且加入map
for(int j=0;j<Math.min(pre.length(),cur.length());j++){
if(pre.charAt(j)==cur.charAt(j)) continue;//如果相同就继续
if(map[pre.charAt(j)-'a'][cur.charAt(j)-'a']==1)break;//说明这组数据已经加入过图了,没必要
map[pre.charAt(j)-'a'][cur.charAt(j)-'a']=1;//值设为1,说明pre.charAt(j)-'a'<cur.charAt(j)-'a'
indegree[cur.charAt(j)-'a']+=1;//向后标记,标记当前数组中的那个不同的字符出现的次数,也就是稍大一点的
flag[pre.charAt(j)-'a']=true;//标记,用来得知在图中已经有了
flag[cur.charAt(j)-'a']=true;
break;//因为我们只要得知第一个不同的字符即可,所以直接break
}
pre=cur;//维护pre
}
}
private static void topolpgy() {
//set中的个数就是所有字符的个数
while (ans.size()<set.size()){
//先找到第一个字符,因为当时标记是 indegree[cur.charAt(j)-'a']+=1;所以第一个字符串的那个不同的字符就漏掉了,也就是最小的那个
int cnt=0;
for(int i=0;i<indegree.length;i++){
if(indegree[i]==0&&flag[i]) cnt++;
}
if(cnt!=1)break;//也就是说如果找到的不是一个,就是错的
//开始找
for(int i=0;i<indegree.length;i++){
if(indegree[i]==0&&flag[i]){//第一次循环找到的就是最小的字符,而后每次操作indegree[j]--,所以再找就是下一个最小的
ans.add((char)('a'+i));//按顺序加入
flag[i]=false;//已经加入结果集,所以设为false
for(int j=0;j<26;j++){//在二维数组中找i这个字符和j字符之间的大小关系
if(map[i][j]==0)continue;//是0说明没关系
indegree[j]--;//将j出现的次数-1
map[i][j]=0;//维护map,置为0
}
}
}
}
}
}
这是代码,是看评论区写的;
没看懂别着急;
一步一步来带你调试,还原程序运行的过程;
build函数
wrt wrf
首先是这两个字符开始比较
map[t][f]=1;(这里使用字符,真正执行是转化成数字哦)
indegree[f]=1;
flag(t)=true;
flag(f)=true;
wrf er
map[w][e]=1;
indegree[e]=1;
flag(w)=true;
flag(e)=true;
er ett
map[r][t]=1;
indegree[t]=1;
flag(r)=true;
flag(t)=true;
ett rftt
map[e][r]=1;
indegree[r]=1;
flag(e)=true;
flag(r)=true;
topolpgy函数
根据indegree[i]==0&&flag[i]第一次找到最小
map[22][4]即map[w][e]=1,且indegree[w]没有标记过
ans.add(w);
indegree[e]--;
map[w][e]=0;
因为上一步操作将indegree[e]--;所以变为0
这次找到的就是map[e][r];
ans.add(e);
indegree[r]--;
map[e][r]=0;
以此类推,其实横纵坐标就保证了有序性。
2110年美团外卖火星第3000号配送站点有26名骑手,分别以大写字母A-Z命名,因此可以称呼这些骑手为黄家骑士特工A,黄家骑士特工B…黄家骑士特工Z,某美团黑珍珠餐厅的外卖流水线上会顺序产出一组包裹,美团配送调度引擎已经将包裹分配到骑手,并在包裹上粘贴好骑手名称,如RETTEBTAE代表一组流水线包裹共9个,同时分配给了名字为A B E R T的5名骑手。请在不打乱流水线产出顺序的情况下,把这组包裹划分为尽可能多的片段,同一个骑手只会出现在其中的一个片段,返回一个表示每个包裹片段的长度的列表。
链接:https://www.nowcoder.com/questionTerminal/80fdfb1b65e149959fc1088bd3f9692e
来源:牛客网
输入描述:
输入数据只有一行,为一个字符串(不包含引号),长度不超过1000,只包含大写字母’A’到’Z’,字符之间无空格。
输出描述:
输出每个分割成片段的包裹组的长度,每个长度之间通过空格隔开
示例1
输入
MPMPCPMCMDEFEGDEHINHKLIN
输出
9 7 8
说明
划分结果为MPMPCPMCM,DEFEGDE,HINHKLIN。
每个骑手最多出现在一个片段中。
像MPMPCPMCMDEFEGDE,HINHKLIN的划分是错误的,因为划分的片段数较少。
这道题是求划分字段开始的下标;
我一开始的想法是将每个字符的下标存入map中,以map<String,List>的形式存储,然后因为不知怎么控制退出条件,然后就没有做下去了
看了评论之后,发现答主双指针用的很妙;
public static void cutLen(String s){
int i=0,j=0,len=s.length();
while (j<len){
char c=s.charAt(j);
int tail=s.lastIndexOf(c);
int pre=j;
i=j+1;
j=tail;
while (i<j){
char inner=s.charAt(i);
j=Math.max(j,s.lastIndexOf(inner));
i++;
}
j++;
System.out.print(j-pre+" ");
}
}
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
String s=sc.nextLine();
cutLen(s);
}
打车派单场景, 假定有N个订单, 待分配给N个司机。每个订单在匹配司机前,会对候选司机进行打分,打分的结果保存在N*N的矩阵A, 其中Aij 代表订单i司机j匹配的分值。
假定每个订单只能派给一位司机,司机只能分配到一个订单。求最终的派单结果,使得匹配的订单和司机的分值累加起来最大,并且所有订单得到分配。
示例1
输入
3
1.08 1.25 1.5
1.5 1.35 1.75
1.22 1.48 2.5
输出
5.25
1 2
2 1
3 3
这道题我走了几个坑,应该是找到最大值,而我找的是每一列的最大值
和二维数组有关的好多都是DFS,回溯;比如机器人路径问题,n皇后问题;
这道题需要行和列一起结合来考虑;
这种DFS问题好难啊;
import java.util.Scanner;
public class Main {
static double[][] order;
static boolean[] isAssigned;
static int[] path;
static int[] resPath;
static double max=-1;
public static void main(String[] args){
Scanner in=new Scanner(System.in);
int n=in.nextInt();
order=new double[n][n];
for(int i=0; i<n; i++){
for(int j=0; j<n; j++){
order[i][j]=in.nextDouble();
}
}
isAssigned=new boolean[n];
path=new int[n];
resPath=new int[n];
dfs(0,path, 0);
System.out.println(String.format("%.2f", max));
for(int i=0; i<n; i++){
System.out.println((i+1)+" "+Math.round(resPath[i]));
}
}
static void dfs(int now, int[] path, double value){
if(now<path.length){
for(int i=0; i<path.length; i++){
if(!isAssigned[i]){
path[now]=i+1;
isAssigned[i]=true;
dfs(now+1, path, value+order[now][i]);
isAssigned[i]=false;
}
}
}else{
if(value>max){
max=value;
System.arraycopy(path,0,resPath,0,path.length);
}
}
}
}
明天调试一遍;
给出两个字符串,分别是模式串P和目标串T,判断模式串和目标串是否匹配,匹配输出 1,不匹配输出 0。模式串中‘?’可以匹配目标串中的任何字符,模式串中的 ’*’可以匹配目标串中的任何长度的串,模式串的其它字符必须和目标串的字符匹配。例如P=a?b,T=acb,则P 和 T 匹配。
链接:https://www.nowcoder.com/questionTerminal/2e2510b2e41e4d3b922416e51afc077b
来源:牛客网
输入描述:
输入第一行包含一个字符串p, (1 ≤ |p| ≤ 20).
输入第二行包含一个字符串t, (1 ≤ |t| ≤ 20).
输出描述:
输出仅包含0和1的整数,0表示p和t不匹配,1表示p和t匹配。
示例1
输入
a?b
ab
输出
0
示例2
输入
a*b
ab
输出
1
示例3
输入
a*b
a(cb
输出
1
这道题力扣好像有;主要是字符串问题,比起KMP还算简单;
import java.util.*;
public class Main
{
public static void main(String[] args){
System.out.print(result());
}
public static int result(){
Scanner sc = new Scanner(System.in);
String str=sc.nextLine();
String str2=sc.nextLine();
char[] strArray=str.toCharArray();
char[] strArray2=str2.toCharArray();
int arrayseq=0;
for(int i=0;i<strArray.length;i++){
if(strArray[i]=='?'){
arrayseq++;
continue;
}
else if(strArray[i]=='*'){
while (true){
if (i<strArray.length-1&& strArray[i+1]=='*') {
i++;
}
else {
break;
}
}
if(i==strArray.length-1){
return 1;
}
else{
for(int j=arrayseq;j<strArray2.length;j++){
if(strArray[i+1]==strArray2[j]){
arrayseq=j-1;
break;
}
}
}
}
else{
if(strArray[i]!=strArray2[arrayseq]){
return 0;
}
}
arrayseq++;
if ((i+1)==strArray.length-1&&arrayseq<strArray2.length-1){
return 0;
}
else if (arrayseq==strArray2.length-1&&(i+1)<strArray.length-1){
return 0;
}
}
return 1;
}
}