【ForOffer】【拼多多2018.08.05-Advance 批】 在线笔试题(旋转的字符串 & 有趣的变换 & 多多社交推荐 )

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值