链接:https://www.nowcoder.com/questionTerminal/3897c2bcc87943ed98d8e0b9e18c4666?answerType=1&f=discussion
来源:牛客网
输入描述:
输入包括多组测试数据。 每组输入第一行是两个正整数N和M(0 < N <= 30000,0 < M < 5000),分别代表学生的数目和操作的数目。 学生ID编号从1编到N。 第二行包含N个整数,代表这N个学生的初始成绩,其中第i个数代表ID为i的学生的成绩 接下来又M行,每一行有一个字符C(只取‘Q’或‘U’),和两个正整数A,B,当C为'Q'的时候, 表示这是一条询问操作,他询问ID从A到B(包括A,B)的学生当中,成绩最高的是多少 当C为‘U’的时候,表示这是一条更新操作,要求把ID为A的学生的成绩更改为B。
输出描述:
对于每一次询问操作,在一行里面输出最高成绩.
输入
5 7 1 2 3 4 5 Q 1 5 U 3 6 Q 3 4 Q 4 5 U 4 5 U 2 9 Q 1 5
输出
5 6 5 9
使用线段树的Java题解。
需要注意两个细节:
- 题目中说明输入有多组测试数据
- 两个整数A和B之间的大小顺序需要考虑,如果"A>B",则需要先调换位置。
import java.util.Scanner; class SegmentTree { private int[] data; private int[] nodes; private int len; public SegmentTree(int[] data) { this.data = data; this.len = data.length; this.nodes = new int[this.len << 2]; this.build(1, 1, data.length); } private void build(int idx, int l, int r) { if (l == r) { this.nodes[idx] = this.data[l - 1]; return; } int mid = (l + r) >> 1; this.build(idx << 1, l, mid); this.build(idx << 1 | 1, mid + 1, r); this.nodes[idx] = Math.max(this.nodes[idx << 1], this.nodes[idx << 1 | 1]); } public void update(int tIdx, int tVal) { if (tIdx <= 0 || tIdx > this.len) { return; } this._update(tIdx, tVal, 1, 1, this.len); } private void _update(int tIdx, int tVal, int idx, int l, int r) { if (l == r) { this.nodes[idx] = tVal; return; } int mid = (l + r) >> 1; if (tIdx <= mid) { this._update(tIdx, tVal, idx << 1, l, mid); } else { this._update(tIdx, tVal, idx << 1 | 1, mid + 1, r); } this.nodes[idx] = Math.max(this.nodes[idx << 1], this.nodes[idx << 1 | 1]); } public int query(int L, int R) { if (L > R) { int temp = L; L = R; R = temp; } if (L <= 0 || R > this.len) { return -1; } return this._query(L, R, 1, 1, this.len); } private int _query(int L, int R, int idx, int l, int r) { if (L == l && R == r) { return this.nodes[idx]; } int mid = (l + r) >> 1; if (R <= mid) { return this._query(L, R, idx << 1, l, mid); } else if (L > mid) { return this._query(L, R, idx << 1 | 1, mid + 1, r); } else { return Math.max(this._query(L, mid, idx << 1, l, mid), this._query(mid + 1, R, idx << 1 | 1, mid + 1, r)); } } } public class Main { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); while (scanner.hasNext()) { int N = scanner.nextInt(); int M = scanner.nextInt(); int[] data = new int[N]; for (int i = 0; i < N; i++) { data[i] = scanner.nextInt(); } SegmentTree maxTree = new SegmentTree(data); for(int i = 0; i < M; i++) { String oper = scanner.next(); int L = scanner.nextInt(); int R = scanner.nextInt(); if ("Q".equals(oper)) { System.out.println(maxTree.query(L, R)); } else if ("U".equals(oper)) { maxTree.update(L, R); } } } scanner.close(); } }
开发一个简单错误记录功能小模块,能够记录出错的代码所在的文件名称和行号。
处理:
1.记录最多8条错误记录,对相同的错误记录(即文件名称和行号完全匹配)只记录一条,错误计数增加;(文件所在的目录不同,文件名和行号相同也要合并)
2.超过16个字符的文件名称,只记录文件的最后有效16个字符;(如果文件名不同,而只是文件名的后16个字符和行号相同,也不要合并)
3.输入的文件可能带路径,记录文件名称不能带路径
首先创建记录错误记录信息的"Record"类
class Record implements Comparable { private String fileName; private String row; private int count; private int pos; .... }
链接:https://www.nowcoder.com/questionTerminal/67df1d7889cf4c529576383c2e647c48?answerType=1&f=discussion
来源:牛客网
- fileName字段为文件名:对于输入的文件名称,使用"split"函数分割得到文件名(不包含路径),这也是为了方便“文件所在的目录不同,文件名和行号相同”的合并操作。
- row字段为行号,记录输入的行号。
- count字段为这类错误记录发生的次数。
- pos字段为错误记录的序号,主要是为了之后的排序(数目相同的情况下,按照输入出现顺序排序)。
通过题意,可以得到错误记录可以通过“文件名+行号”来唯一区分,对应于Record类,就是由字段"fileName+row"可以区分不同的错误记录。因此,我们需要重写Record类中的"equals"和"hashcode"方法。在统计不同错误记录的次数时,我们使用HashMap进行统计。
此外,为了后续使用"Arrays.sort()"方法进行排序,Record类还实现了"Comparable"接口,并且定义降序排序规则。最后,在输出的时候,需要注意如果文件名长度超过16位,只需输出后16位。
import java.util.Arrays; import java.util.HashMap; import java.util.Map; import java.util.Scanner; class Record implements Comparable { private String fileName; private String row; private int count; private int pos; public Record(String fileName, String row) { this.fileName = fileName; this.row = row; } public int getPos() { return pos; } public void setPos(int pos) { this.pos = pos; } public String getFileName() { return fileName; } public String getRow() { return row; } public int getCount() { return count; } public void setFileName(String fileName) { this.fileName = fileName; } public void setRow(String row) { this.row = row; } public void setCount(int count) { this.count = count; } @Override public int compareTo(Object o) { Record record = (Record) o; return record.count - this.count; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } else if (obj == null) { return false; } else { Record record = (Record) obj; if (this.fileName.equals(record.getFileName()) && this.row.equals(record.getRow())) { return true; } } return false; } @Override public int hashCode() { return this.fileName.hashCode() + this.row.hashCode(); } @Override public String toString() { String fileName = this.fileName; if (fileName.length() > 16) { fileName = fileName.substring(this.fileName.length() - 16); } return fileName + " " + this.row + " " + this.count; } } public class Main { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); Map<Record, Integer> errorCount = new HashMap<Record, Integer>(); int pos = 0; while (scanner.hasNext()) { String errorInfo = scanner.nextLine(); String[] errorInfos = errorInfo.split(" "); String[] paths = errorInfos[0].split("\\"); Record record = new Record(paths[paths.length - 1], errorInfos[1]); if (!errorCount.containsKey(record)) { record.setPos(pos++); errorCount.put(record, 0); } errorCount.put(record, errorCount.get(record) + 1); } scanner.close(); Record[] records = new Record[errorCount.size()]; for (Record record : errorCount.keySet()) { record.setCount(errorCount.get(record)); records[record.getPos()] = record; } Arrays.sort(records); for (int i = 0; i < 8 && i < records.length; i++) { System.out.println(records[i]); } } }
扑克牌游戏大家应该都比较熟悉了,一副牌由54张组成,含3~A,2各4张,小王1张,大王1张。牌面从小到大用如下字符和字符串表示(其中,小写joker表示小王,大写JOKER表示大王):)
3 4 5 6 7 8 9 10 J Q K A 2 joker JOKER
输入两手牌,两手牌之间用“-”连接,每手牌的每张牌以空格分隔,“-”两边没有空格,如:4 4 4 4-joker JOKER
请比较两手牌大小,输出较大的牌,如果不存在比较关系则输出ERROR
基本规则:
(1)输入每手牌可能是个子,对子,顺子(连续5张),三个,炸弹(四个)和对王中的一种,不存在其他情况,由输入保证两手牌都是合法的,顺子已经从小到大排列;
(2)除了炸弹和对王可以和所有牌比较之外,其他类型的牌只能跟相同类型的存在比较关系(如,对子跟对子比较,三个跟三个比较),不考虑拆牌情况(如:将对子拆分成个子)
(3)大小规则跟大家平时了解的常见规则相同,个子,对子,三个比较牌面大小;顺子比较最小牌大小;炸弹大于前面所有的牌,炸弹之间比较牌面大小;对王是最大的牌;
(4)输入的两手牌不会出现相等的情况。
答案提示:
(1)除了炸弹和对王之外,其他必须同类型比较。
(2)输入已经保证合法性,不用检查输入是否是合法的牌。
(3)输入的顺子已经经过从小到大排序,因此不用再排序了.
import java.util.ArrayList; import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); String[] left,right; String[] line; String nextLine,outString; while(sc.hasNext()){ nextLine = sc.nextLine(); //有王炸就王炸最大 if(nextLine.contains("joker JOKER")){ outString = "joker JOKER"; }else{ //拆分 先拆成左右 再拆成单排 line = nextLine.split("-"); left = line[0].split(" "); right = line[1].split(" "); //炸弹最大 if(left.length == 4 && right.length != 4){ outString = line[0]; }else if(right.length == 4 && left.length != 4){ outString = line[1]; } // 牌数相同的情况下比较最小的牌的大小,compare方法返回牌所对应的值 else if(right.length == left.length){ if(count(left[0])>count(right[0])){ outString = line[0]; } else{ outString = line[1]; } }else{ outString = "ERROR"; } } System.out.println(outString); } } //2-JOKER 按大小返回2-16 private static int count(String str) { return "345678910JQKA2jokerJOKER".indexOf(str);