First Question:
旋转的字符串
题目描述
给定一个字符串,按顺时针顺序输出为一个正方形,具体规则如下;
1.从上边开始,上边从左到右
2.然后到右边,右边从上到下
3.然后是下边,下边从右到左
4.最后是左边,左边从下到上
输入描述
输入一行,包含4K(K为整数,1<=K<=10)个小写字母。
输出描述
输出K+1行,按上面的规则输出正方形,正方形内部用空格填充。
示例
输入:
abdcefghijklmnop
输入:
abcde
p f
o g
n h
mlkji
思路简图
将需要输出的这个正方形矩阵,进行分块,处理,见图。
同一样色的分成一块看,那么使用while 循环嵌套while循环,就能很好实现出来。
A | B | C |
H |
| D |
G | F | E |
A | B | C | D | E |
P |
|
|
| F |
O |
|
|
| G |
N |
|
|
| H |
M | L | K | J | I |
代码 &注释
package com.Mukvin.PingDuoDuo;
import java.util.Scanner;
public class RotateString {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String string = scanner.nextLine();
char[][] rotateMatrix = Rotate(string);
for(int i = 0 ; i< rotateMatrix.length;i++) {
for(int j = 0 ; j <rotateMatrix[0].length;j++) {
System.out.print(rotateMatrix[i][j]);
}
System.out.println();
}
scanner.close();
}
private static char[][] Rotate(String string) {
//如果长度不是4的倍数,说明不能打印出一个正方形
if (string.length()%4 !=0) {
return null;
}
int size = string.length()/4;
//正方形矩阵的尺寸是比size大1
char[][] tmp = new char[size+1][size+1];
//初始化要打印的矩阵
for (int i = 0; i < tmp.length; i++) {
for (int j = 0; j < tmp[0].length; j++) {
tmp[i][j] = ' ';
}
}
int index = 0;//标记字符位置
int i = 0 ,j = 0;//矩阵的行为 i,列为j
//主要处理逻辑,其中分成了四个大块,具体参看简图,解释
while(index < string.length()) {
while(index < size ) {
tmp[i][j++] = string.charAt(index++);
}
while(size <= index && index <2*size) {
tmp[i++][j] = string.charAt(index++);
}
while(2*size <= index && index < 3*size) {
tmp[i][j--] = string.charAt(index++);
}
while(3*size<=index && index < 4*size) {
tmp[i--][j] = string.charAt(index++);
}
}
return tmp;
}
}
Second Question:
有趣的变换
题目描述
字符串形式的正整数(可能包含前缀0, 1<=length<=10),先将这个字符串拆成两部分,接着可以在这两部分中分别加入一个小数点也可以不加入,分别形成一个整数或小数,找出所有经“拆分”和“变化”两次操作后所有可能组合的数目。
要求:
1、对于新形成的整数和小数,不可包含多余的前缀0,比如010和010.1不合法;
2、对于小数,不可包含多余的后缀0,比如0.10不合法;
3、.1和1.这样的小数不合法。
输入描述
输入一行。包含一个字符串形式的正整数。
输出描述
输出为一行,找出经过“拆分”和“变化”后的所有组合的数目。
示例
输入:
123
输出:
4
说明:
可能的组合如下:
[[1, 23], [12, 3], [1.2, 3], [1, 2.3]]
输入:
00011
输出:
2
说明:
可能的组合如下:
[[0.001, 1], [0, 0.011]]
思路
此题最为头疼的地方,就是包含0的处理。
本体的关键,其实是在于分成了两个字串之后,在分别统计,并且就着包含'0'的情况进行分析。
1、如果原先字符串string包含的长度为0,则不用进行,直接返回结果数为0.
(如果原先字符串string包含的长度为1(这个地方,其实是放在了子字串统计中在进行讨论),自然也是返回结果数1.在主函数中,不体现,看下面代码就可明白和理解了。)
2.如果原先字符串长度不为0,1,且,其分出来的 子字符串 (!!!)首尾不包含0(重要!!!!),那么可以小数点分出来的结果就有string本身一个,然后在加上了string中间空隙有多少,也即C(string.length()-1,1)=string.length-1.那么最终结果就是string.length()了。
示例:“123456”那么在其中就可点1.23456 , 12.3456 , 123.456 , 1234.56 ,12345.6,以及自身123456,有6个情况哦!
3、如果string分出来的子字符串首尾包含0,就要重点分析啦~
以下为示例:
'010':不可能点小数点的。
'100':也是只能一个,是它本身'100',这个地方要注意,容易晕的,'100'是不可能再分'10.0',是不满足多余后缀0的。
'001':也是只能一个,是在第一个'0'的位置后点一个小数点,即‘0.01’,其他有多个'0'同理.
代码实现&注释
package com.Mukvin.PingDuoDuo;
import java.util.Scanner;
public class InterestingChange {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String string = scanner.nextLine();
System.out.println(getCount(string));
scanner.close();
}
private static int getCount(String string) {
int count = 0 ;
//字符串长度为0,不能分了,只能返回0
if (string.length() == 0) {
return count;
}
for(int i = 0 ;i < string.length();i++) {
//字符串的总结果就是两个子字串得到的结果的乘积(这里是组合数学的中的乘法法则)
//****想到了子字符串分开统计计算,就是解题的最大关键,不然很容易晕,到底要怎么处理和统计字符串****
//此处应该可以优化
if (subSeperateCount(string.substring(0, i))
*subSeperateCount(string.substring(i,string.length())) != 0) {
count += subSeperateCount(string.substring(0, i))
*subSeperateCount(string.substring(i,string.length()));
}
}
return count;
}
//分离之后,字串的可分,可加小数点的情况统计
private static int subSeperateCount(String substring) {
//如果分离出来的不管这个数是不是零,长度为一,就只能分出一种情况
if (substring.length() == 1) {
return 1;
}
//分离出来,如果字串中,首尾只要包含一个有0,这种情况是主要要讨论的
//实例:"000" 首尾都是0,结果是不存在的,返回0
//"10" 注意1.0 是不合法的,所以只要尾巴含有0,那么也只能分出一个情况,再比如100,也只能是分成100,而不能10.0
//"01" 只能分出0.1 ,是一种,001 只能是分出一中0.01
//以上,就是该题目最核心的处理地方
//而如果字符串中,不包含'0',比如123456,那么可以分成了该字符串的(除却了首尾的小数点不可点)中间插空点,
//可以点有是str.len -1,但最终结果要注意,还要加上这个字符串本身 1,所以如果字符串不包含'0'那么,结果可以分出str.len的数目
if (substring.startsWith("0") || substring.endsWith("0")) {
//这个地方,上面的startWith 和 charAt()可以相互替换
//首尾都是0,那么结果就是0,排除了首尾都是0的情况,剩下,要么头有0,要么尾有0,结果就是只有一种
if (substring.charAt(0)=='0' && substring.charAt(substring.length()-1) == '0') {
return 0;
}else {
return 1;
}
}else {
//如果首尾都不是0开头
//这里不要困惑,如果中间包含0的情况,中间包含0的情况,就只是小数点在字符串中间移动得到的情况,最后再在加上自己本身
return substring.length();
}
}
}
Third Question:
多多社交推荐
题目描述
给定一个含有N个用户的朋友列表,对于一个指定用户,找出这个用户最可能认识的人,
最可能认识的人的定义为这个人和当前用户不是朋友关系,但有最多的共同朋友。
朋友关系是相互的(如果A列出B为朋友,B也会列出A为朋友),
如果两个用户都有同样多的共同朋友,返回用户序号(从0开始)小的用户。
如果用户和所有人都没有共同朋友,返回-1。
输入描述
第一行两个数,第一个数表示用户数目N(N小于等于100),第二个数为需要判断的用户序号。第2至N+1行表示序号为0到序号为N-1的每个用户的朋友序号列表,每个列表长度小于100。
输出描述
给定用户最可能认识的人的用户序号
示例
输入:
5 0
1 2 3
0 4
0 4
0 4
1 2 3
输出:
4
说明:
用户0与用户1、2、3都相互认识,用户4与用户1、2、3都相互认识
解题思路
一开始,乍一看,还以为是要用图的遍历什么,来关联这些个人的朋友,太复杂了!
转头想了想还是不可能实现,而且用图去考虑思索,实在是不知道要怎么去判定了相同朋友多的才是可能的朋友。
放弃了图的想法。
最后,认真关注到了说明解释。
发现,其实说明已经是在暗示我们应该处理方法,一开始,我陷入到了1->0 4 , 2 ->0 4 , 3-> 0 4 ,还想着把这三个也处理下,但是说明只是给了我们0 和 4 ,没有太多的必要去考虑1 2 3 用户干嘛,发现只要用hashmap。
第一步,设置一个hashmap用于存储 用户 和 他对应的朋友列表!
也即是hashMap<integer, ArrayList<integer>>>
第二步,在处理输入的同时,做一个判断,不在目标用户的朋友列表中的用户,该用户的朋友才能进入设置的 hashmap中,因为只要是在目标用户的朋友圈中,那都已经是朋友了,题意也说明了这一点,提前处理好hashmap,接下来的工作就好做了。
第三步,已经是知道了目标用户的朋友圈,拿出来。
做一个迭代器,或者是使用Map.Entry<?,?> 去设置遍历条件,来遍历hashmap.
第三.一步,不比对是自己的朋友圈,(自己在输入的时候,为了判断方便,将自己朋友圈也放在了map中),只比对不是自己的朋友圈,有相同的朋友,设置一个count变量去标记,在循环外设置标记最大相同的朋友数。
第三.二步,实时更新最大朋友圈数,更新最可能是朋友的键值索引index.
第三.三步,一定一定注意,如果有多个朋友圈数一样,这种情况也要考虑在内,选择最早的朋友圈一样的用户索引即可。后续如果题目变更或者是其他类似的,也可以进行相应的变化。
代码&注释
package com.Mukvin.PingDuoDuo;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
public class ComunicationRecomendation {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int N = scanner.nextInt();//N个用户
int target = scanner.nextInt();//目标用户(要找朋友的人)
//设置存储用户和对应的朋友列表的map
HashMap<Integer, ArrayList<Integer>> totalMap = new HashMap<>();
scanner.nextLine();//处理换行进入循环输入,如果不添加,会提示报错 :java.lang.NumberFormatException: For input string: ""
for(int i = 0;i < N;i++ ) {
String tempNumStr = scanner.nextLine();
ArrayList<Integer> tempNumList = new ArrayList<>();//存储各个用户对应的朋友列表
for(String str : tempNumStr.split(" ")) {
//将得到的"1 2 3"切割,做成一个字符串数组
tempNumList.add(Integer.parseInt(str));
}
//升级下map:升级规则如下
//如果当前输入,就是用户自己,那么将他的所有朋友放进map中
//如果当前的输入的不是用户自己,而是别的用户,但是他们的朋友列表如果包含了目标用户,则不放tempList
//也即,只要不包含了目标用户的,输入用户他的朋友列表都放进来,那些才是目标用户有可能潜在的朋友
if (target == i || !tempNumList.contains(target)) {
totalMap.put(i, tempNumList);
}
}
//获得目标用户的他原先的朋友列表,以便能在后面的比对,别人的不包含目标用户的朋友列表
ArrayList<Integer> targetFriends = totalMap.get(target);
System.out.println(findPossibleFriend(target,totalMap,targetFriends));
scanner.close();
}
private static int findPossibleFriend(int target, HashMap<Integer, ArrayList<Integer>> totalMap,
ArrayList<Integer> targetFriends) {
//判断用户的可能朋友,要找类似朋友最多的那个,设定三个指标。
int maxSameFriends = 0; //表示最多共同朋友数
int index = 0; //确定目标用户可能朋友的索引
//遍历map有三种方法(使用keySet,使用entrySet,使用迭代器),这里使用entrySet
for(Map.Entry<Integer,ArrayList<Integer>> entry : totalMap.entrySet()) {
ArrayList<Integer> tempFriends = entry.getValue();
int tempCount = 0;//临时变量,表示每个用户与目标用户的相同朋友个数
//如果entry的一个用户不是target,则进行比对
if (entry.getKey() != target) {
for(int i = 0 ;i < tempFriends.size();i++) {
//比对相似用户,如果有一个一致则maxSameFriends++
if (targetFriends.contains(tempFriends.get(i))) {
tempCount++;
}
}
}
//更新maxSameFriends与index
if(tempCount > maxSameFriends ) {
maxSameFriends =tempCount;
index = entry.getKey();
}
//假设这个时候有多个人的共同朋友数是一样的,则只取前面最开始朋友数相同,但是索引下标最小的那个人
if (maxSameFriends == tempCount && entry.getKey() < index) {
index = entry.getKey();
}
}
return index;
}
}
Fourth Question:
升序降序取数游戏(coding..... && explaining...)
题目描述
多多鸡正在玩一个取卡片的游戏,有n个标有正整数的卡片,从左到右依次排列,每轮取卡哆哆鸡必须满足升序规则和降序规则中的一种:
升序规则:取出的右边卡片数值大于左边卡片数值;
降序规则:取出的右边卡片数值小于左边卡片数值;
帮多多鸡算算最少需要多少轮游戏可以取完所有的卡片。
输入描述
输入为两行,第一行为卡片个数n(1<=n<=50),第二行为长度为n的正整数序列。
输出描述
一个整数,代表最少的轮次。
示例
输入:
5
3 5 2 4 1
输出:
2
说明:
第一轮321,第二轮54。
----------------------------------------------------------------------
输入:
6
1 2 4 3 3 3
输出:
3
说明:
第一轮13,第二轮23,第三轮43。
思路
本文博客为原创编辑,如有转载,请注明出处。博文原地址:https://blog.csdn.net/mukvintt/article/details/81451204