k个一组翻转链表
题目一描述
给定一个链表,将链表中的k个元素进行翻转,最后不满足k个元素的整数倍的元素,不进行翻转。
例如:
输入:1->2->3->4->5
k=2时: 返回2->1->4->3->5
k=3时:返回3->2->1->4->5
题目一分析
该题目是一道困难的题目,但是对于链表这种数据结构的题目一般都不是特别难。可以使用一个指针窗口进行翻转窗口内的所有节点,但是这样的做题需要多个指针,比较乱。
我使用额外的空间辅助翻转链表,将链表中的k个元素为一组,压入栈中,一次将其弹出挂载到一个新的链表中,需要注意的是小心链表成环问题。
代码如下
//将将链表中的元素以k为单位进行反转
public static ListNode reverseKGroup(ListNode head, int k) {
ListNode root = new ListNode(-1);
ListNode curnode = head;
ListNode pre = root;
pre.next = head;
//使用一个栈结构进行反转。每次入栈k个元素,然后弹出元素
Stack<ListNode> stack = new Stack<>();
while(curnode!=null){
int temp = k;
ListNode tempNode = curnode;
//入栈链表的k个元素
while(tempNode!=null&&temp-->0){
stack.push(tempNode);
tempNode = tempNode.next;
}
//如果最后不满足的几个元素不入栈操作
if(tempNode==null&&temp!=0){
pre.next = curnode;
break;
}
//反转链表,即将元素从栈中弹出
curnode = tempNode;
while(!stack.isEmpty()){
pre.next = stack.pop();
pre = pre.next;
}
//必须将其设置为nul否则会引起链表成环
pre.next = null;
}
return root.next;
}
用户喜好
题目二描述
题目描述的相当复杂,阅读题目我都开始怀疑自己的中文水平了。大致说明一下题目的意思:第一行表示n个用户,第二行表示5个用户对某个文章的喜好程度,第三行表示给出的查询条数q,需要查询的是后面的q行,每行表示l到r之间用户喜好为k的用户数量
例如:
5
1 2 3 3 5
3
1 2 1
2 4 5
3 5 3
输出是:
1
0
2
题目二分析
题目读完就差不多想要放弃了吧,不过为了大厂还是要多准备的,一开始想着将用户喜好放在一个容器中,然后根据每个查询条件去匹配原来的容器,将查询结果返回,当然是天真,时间复杂度太高。
更改策略:使用一个map将用户喜好以及对应的下标记录下来,相当于一个分组处理过程,遍历起来就快了很多。
代码如下
暴力搜索,当然不尽人意
private static void userHouby() throws IOException {
BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
int n = Integer.valueOf(bf.readLine());
//将用户喜好放在一个数组中,后面进行匹配
String[] num = bf.readLine().split(" ");
int q = Integer.valueOf(bf.readLine());
StringBuilder sb = new StringBuilder();
for(int i=0;i<q;i++){
String[] temp = bf.readLine().split(" ");
int left = Integer.valueOf(temp[0]);
int right = Integer.valueOf(temp[1]);
int k = Integer.valueOf(temp[2]);
int res= searchNum(num,left,right,k);
sb.append(res+"\n");
}
System.out.println(sb.toString());
}
//用户喜好的数组,当前需要查询的范围left,right以及喜好是k
public static int searchNum(String[] num,int left,int right,int k){
int res = 0;
for(int i=left-1;i<right;i++){
int temp = Integer.valueOf(num[i]);
if(temp == k)res++;
}
return res;
}
优化算法
//使用map将用户的喜好记录下来
private static void customerHoby() throws IOException {
BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
int n = Integer.valueOf(bf.readLine());
Map<String, List<Integer>> map = new HashMap<>();
String[] num = bf.readLine().split(" ");
//记录用户的喜好以及对应的下标位置
for(int i = 0;i<n;i++){
List<Integer> list = null;
if(map.containsKey(num[i])){
list = map.get(num[i]);
}else {
list = new ArrayList<>();
}
list.add(i);
map.put(num[i],list);
}
int q = Integer.valueOf(bf.readLine());
StringBuilder sb = new StringBuilder();
//处理q条查询语句
for(int i=0;i<q;i++){
String[] temp = bf.readLine().split(" ");
if(map.containsKey(temp[2])){
int res = searchList(map.get(temp[2]),Integer.valueOf(temp[0]),Integer.valueOf(temp[1]));
sb.append(res+"\n");
}else{
sb.append(0+"\n");
}
}
System.out.println(sb.toString());
}
//查看链表中有多少个元素位置满足要求
public static int searchList(List<Integer> list,int left,int right){
int sum = 0;
for(int i=0;i<list.size();i++){
if(list.get(i) <= right-1 && list.get(i) >= left-1){
sum++;
}else if(list.get(i)>right){
break;
}
}
return sum;
}
手串问题
题目三描述
题目依旧复杂,想要阅读以下题目的可以去看看题目的描述。
输入第一行为n个串珠,每m个之间的颜色不能重复,一共有c中颜色
以下的n行为每个串珠的颜色分布。
例如:
5 2 3
3 1 2 3
0
2 2 3
1 2
1 3
输出是:
2
解释以下:有5个串珠,第一个串珠3中颜色,第二个串珠没有颜色,第三个串珠有两种颜色,第四个第五个有一种颜色
每两个之间不能够有重复的颜色,第三个珠子和第四个珠子都有2,第五个珠子和第一个珠子都有3,因此两个串珠不符合要求。
题目三分析
有参考别人的讲解,做题的思路还是需要多加的练习的。对于颜色和串珠的信息是要使用容器存储起来的,题目多了一般就会知道将哪一个特征作为key,哪一个特征作为value存储起来。该题目是将颜色作为key,一个颜色对应的串珠组成一个链,如果链中的串珠小于要求的m说明不符合要求,最后将不符合要求的个数累加起来。
代码如下
public static void main(String[] args)throws IOException {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int m = sc.nextInt();
int c = sc.nextInt();
//创建map存储颜色以及对应的串珠信息,并初始化链表
Map<Integer,LinkedList<Integer>> map = new HashMap<>();
for(int i=0;i<=c;i++){
map.put(i,new LinkedList<>());
}
//将颜色与串珠信息添加到容器中
for(int i=0;i<n;i++){
int temp = sc.nextInt();
for(int j=0;j<temp;j++){
int color = sc.nextInt();
LinkedList<Integer> list = map.get(color);
list.add(i);
}
}
//不符合要求的个数
int error = 0;
//一共有c种颜色,每种颜色进行判断,找出不符合要求的个数
for(int i=1;i<=c;i++){
LinkedList<Integer> tempList = map.get(i);
for(int j=0;j<tempList.size();j++){
//对于不是最后一个串珠,那么就计算相邻元素的信息
//如果是最后一个元素的信息,就需要计算第一个串珠的信息,因为这是一个环状的手串
if (j+1<tempList.size()&&tempList.get(j+1) - tempList.get(j)<m) {
error++;
break;
}else if(j+1==tempList.size()&&tempList.get(0) - tempList.get(j)+n<m){
error++;
break;
}
}
}
System.out.println(error);
}