1、迷宫
public class Main {
static int count = 0;
public static void main(String[] args) {
char[][] ch = {
{ 'U', 'D', 'D', 'L', 'U', 'U', 'L', 'R', 'U', 'L' },
{ 'U', 'U', 'R', 'L', 'L', 'L', 'R', 'R', 'R', 'U' },
{ 'R', 'R', 'U', 'U', 'R', 'L', 'D', 'L', 'R', 'D' },
{ 'R', 'U', 'D', 'D', 'D', 'D', 'U', 'U', 'U', 'U' },
{ 'U', 'R', 'U', 'D', 'L', 'L', 'R', 'R', 'U', 'U' },
{ 'D', 'U', 'R', 'L', 'R', 'L', 'D', 'L', 'R', 'L' },
{ 'U', 'L', 'L', 'U', 'R', 'L', 'L', 'R', 'D', 'U' },
{ 'R', 'D', 'L', 'U', 'L', 'L', 'R', 'D', 'D', 'D' },
{ 'U', 'U', 'D', 'D', 'U', 'D', 'U', 'D', 'L', 'L' },
{ 'U', 'L', 'R', 'D', 'L', 'U', 'U', 'R', 'R', 'R' }
};
for (int i = 0; i < ch.length; i++) {
for (int j = 0; j < ch[i].length; j++) {
dfs(i, j, ch);
}
}
System.out.println(count);
}
public static void dfs(int x, int y, char[][] ch) {
int m = ch.length;
int n = ch[0].length;
if (x < 0 || y < 0 || x > m - 1 || y > n - 1) {
count++;
return;
}
char flag = ch[x][y];
if (ch[x][y]=='p') {
return;
}
ch[x][y] = 'p';
if (flag == 'U') {
dfs(x-1, y, ch);
}
if (flag =='L') {
dfs(x, y-1, ch);
}
if (flag=='D') {
dfs(x+1, y, ch);
}
if (flag =='R') {
dfs(x, y+1, ch);
}
ch[x][y] = flag;
}
}
总结:A组今年第一题就这么恶心,没做出来直接看题解,是道dfs,但是中间要检测是否走过,走过的直接退出,这里用了一个flag变量来标记,刚进来就记录原本的方向,然后赋值成P标识走过了,如果下次进来if成立为p就直接return,说明走过了,然后返回上一层把flag赋值回去(递归的时候每层的变量都是独立的 所以不存在下层的flag会吧上层覆盖,所以我们层都用自己的flag记录
2、9数算式
观察如下的算式:
9213×85674=789314562
左边的乘数和被乘数正好用到了 11 ~ 99 的所有数字,每个 11 次。 而乘积恰好也是用到了 11 ~ 99 的所有数字,并且每个 11 次。
请你借助计算机的强大计算能力,找出满足如上要求的 99 数算式一共有多少个?
注意:
- 总数目包含题目给出的那个示例。
- 乘数和被乘数交换后作为同一方案来看待。
import java.util.Scanner;
// 1:无需package
// 2: 类名必须Main, 不可修改
import java.util.HashSet;
//import java.util.Scanner;
import java.util.Set;
public class Main {
private static int[] a = {1,2,3,4,5,6,7,8,9};
private static int ans;
public static void main(String[] args) {
// Scanner scan = new Scanner(System.in);
// f(0);
// System.out.println(ans);
System.out.println(3250/2);
// scan.close();
}
private static void f(int k) {
if(k == 9) {
for (int i = 1; i < 9; i++) {
check(i);
}
}
for (int i = k; i < a.length; i++) {
int t = a[i];
a[i] = a[k];
a[k] = t;
f(k+1);
t = a[i];
a[i] = a[k];
a[k] = t;
}
}
private static void check(int len) {
int num1 =0;
int num2 = 0;
int t = 1;
for (int i = len-1; i >= 0; i--) {
num1 += a[i]*t;
t*=10;
}
t = 1;
for (int i = a.length-1; i >= len; i--) {
num2 += a[i]*t;
t*=10;
}
int num3 = num1*num2;
String str = num3+"";
if(str.length()!=9)return;
Set<Character> set = new HashSet<>();
for (int i = 0; i < str.length(); i++) {
if (str.charAt(i)!='0') {
set.add(str.charAt(i));
}
}
if(set.size() == 9) {
ans++;
// System.out.printf("%d * %d == %d\n",num1,num2,num3);
}
}
}
总结:全排列,但是这个check比较难 第一个for是前面的数字,第二个是后面的数,然后相乘为9位数字而且不重复,就能ans++(放到set里面看有没有重复)
3、字母组串
由 A,B,C 这3个字母就可以组成许多串。 比如:"A","AB","ABC","ABA","AACBB" ....填空
现在,小明正在思考一个问题: 如果每个字母的个数有限定,能组成多少个已知长度的串呢?
他请好朋友来帮忙,很快得到了代码, 解决方案超级简单,然而最重要的部分却语焉不详。
{
// a个A,b个B,c个C 字母,能组成多少个不同的长度为n的串。
static int f(int a, int b, int c, int n)
{
if(a<0 || b<0 || c<0) return 0;
if(n==0) return 1;
return ________________________________; //填空
}
public static void main(String[] args)
{
System.out.println(f(1,1,1,2));
System.out.println(f(1,2,3,3));
}
}
答案:f(a-1,b,c,n-1)+f(a,b-1,c,n-1)+f(a,b,c-1,n-1)
总结:看到这种最后小于0的肯定是递归的递减,有3种情况,a减少,b减少,c减少然后把他们的数量相加就是各种情况的总和。
4、最大公共子串
最大公共子串长度问题就是: 求两个串的所有子串中能够匹配上的最大长度是多少。
比如:"abcdkkk" 和 "baabcdadabc", 可以找到的最长的公共子串是"abcd",所以最大公共子串长度为 4。下面的程序是采用矩阵法进行求解的,这对串的规模不大的情况还是比较有效的解法。
请分析该解法的思路,并补全划线部分缺失的代码。填空
import java.util.Scanner;
public class Main
{
static int f(String s1, String s2)
{
char[] c1 = s1.toCharArray();
char[] c2 = s2.toCharArray();
int[][] a = new int[c1.length+1][c2.length+1];
int max = 0;
for(int i=1; i<a.length; i++){
for(int j=1; j<a[i].length; j++){
if(c1[i-1]==c2[j-1]) {
a[i][j] = __________________________;
if(a[i][j] > max) max = a[i][j];
}
}
}
return max;
}
public static void main(String[] args){
int n = f("abcdkkk", "baabcdadabc");
System.out.println(n);
System.out.println(f("aaakkkabababa", "baabababcdadabc"));
System.out.println(f("abccbaacbcca", "ccccbbbbbaaaa"));
System.out.println(f("abcd", "xyz"));
System.out.println(f("ab", "ab"));
}
}
答案:a[i-1][j-1]+1
总结:这题是动态规划,新的东西用到旧的,根据题大概可以理解到他是竖着遍历第一个字符串,横着遍历第二个,连续相等的话是斜着加的。从而可以推出当元素连续相等的时候,后面右下角的等于右上角元素加1。
5、购物单
小明刚刚找到工作,老板人很好,只是老板夫人很爱购物。老板忙的时候经常让小明帮忙到商场代为购物。小明很厌烦,但又不好推辞。
这不,大促销又来了!老板夫人开出了长长的购物单,都是有打折优惠的。
小明也有个怪癖,不到万不得已,从不刷卡,直接现金搞定。
现在小明很心烦,请你帮他计算一下,需要从取款机上取多少现金,才能搞定这次购物。
取款机只能提供 100100 元面额的纸币。小明想尽可能少取些现金,够用就行了。 你的任务是计算出,小明最少需要取多少现金。
以下是让人头疼的购物单,为了保护隐私,物品名称被隐藏了。
**** 180.90 88折
**** 10.25 65折
**** 56.14 9折
**** 104.65 9折
**** 100.30 88折
**** 297.15 半价
**** 26.75 65折
**** 130.62 半价
**** 240.28 58折
**** 270.62 8折
**** 115.87 88折
**** 247.34 95折
**** 73.21 9折
**** 101.00 半价
**** 79.54 半价
**** 278.44 7折
**** 199.26 半价
**** 12.97 9折
**** 166.30 78折
**** 125.50 58折
**** 84.98 9折
**** 113.35 68折
**** 166.57 半价
**** 42.56 9折
**** 81.90 95折
**** 131.78 8折
**** 255.89 78折
**** 109.17 9折
**** 146.69 68折
**** 139.33 65折
**** 141.16 78折
**** 154.74 8折
**** 59.42 8折
**** 85.44 68折
**** 293.70 88折
**** 261.79 65折
**** 11.30 88折
**** 268.27 58折
**** 128.29 88折
**** 251.03 8折
**** 208.39 75折
**** 128.88 75折
**** 62.06 9折
**** 225.87 75折
**** 12.89 75折
**** 34.28 75折
**** 62.16 58折
**** 129.12 半价
**** 218.37 半价
**** 289.69 8折
需要说明的是,8888 折指的是按标价的 88%88 计算,而 88 折是按 80%80 计算,余者类推。 特别地,半价是按 50%50 计算。
请输出小明要从取款机上提取的金额,单位是元。
题解:这题考得就是excel的使用,我们直接算太慢了,最快的就是用excel表格。
6、纸牌三角形
A,2,3,4,5,6,7,8,9 共 99 张纸牌排成一个正三角形(AA 按 11 计算)。要求每个边的和相等。 下图就是一种排法。
这样的排法可能会有很多。
如果考虑旋转、镜像后相同的算同一种,一共有多少种不同的排法呢?
请你计算并提交该数字。
import java.util.Scanner;
// 1:无需package
// 2: 类名必须Main, 不可修改
public class Main {
static int ans =0;
static int[] a = {1,2,3,4,5,6,7,8,9};
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
//在此输入您的代码...
fun(0);
System.out.println(ans/6);
scan.close();
}
static void fun(int start)
{
if(start==a.length){
if(check()){
ans++;
}
}
for(int i =start;i<a.length;i++){
int temp = a[start];
a[start] = a[i];
a[i] = temp;
fun(start+1);
temp = a[start];
a[start] = a[i];
a[i] = temp;
}
}
static boolean check()
{
int x1 =a[0]+a[1]+a[2]+a[3];
int x2 =a[3]+a[4]+a[5]+a[6];
int x3 =a[6]+a[7]+a[8]+a[0];
if(x1==x2&&x2==x3)
{
return true;
}
return false;
}
}
总结:全排列。固定模板,但是有坑,他旋转和对称都算一种,那么对称要除2,旋转又有3种情况,所有ans一共要除以6
7、取位数
求1个整数的第k位数字有很多种方法。 以下的方法就是一种。填空
import java.util.*;
public class Main
{
static int len(int x){
if(x<10) return 1;
return len(x/10)+1;
}
// 取x的第k位数字
static int f(int x, int k){
if(len(x)-k==0) return x%10;
return ______________________; //填空
}
public static void main(String[] args)
{
int x = 23513;
//System.out.println(len(x));
System.out.println(f(x,3));
System.out.println(f(893275,2));
}
}
答案:f(x/10,k)
总结:当len(x)-k==0才return,大概率递归,递归要满足这个条件只能len减小或k变大,k是固定的,所以只能len(x)减小了,所以每次减小x/10,k不变
8、分巧克力
儿童节那天有 K 位小朋友到小明家做客。小明拿出了珍藏的巧克力招待小朋友们。
小明一共有 NN 块巧克力,其中第 ii 块是 H_i \times WiHi×Wi 的方格组成的长方形。为了公平起见,
小明需要从这 NN 块巧克力中切出 K 块巧克力分给小朋友们。切出的巧克力需要满足:
-
形状是正方形,边长是整数;
-
大小相同;
例如一块 6x5 的巧克力可以切出 6 块 2x2 的巧克力或者 2 块 3x3 的巧克力。
当然小朋友们都希望得到的巧克力尽可能大,你能帮小明计算出最大的边长是多少么?
输入描述
第一行包含两个整数 N,KN,K (1 \leq N, K \leq 10^51≤N,K≤105)。
以下 N 行每行包含两个整数 H_i,W_iHi,Wi (1 \leq H_i, W_i \leq 10^51≤Hi,Wi≤105)。
输入保证每位小朋友至少能获得一块 1x1 的巧克力。
输出描述
输出切出的正方形巧克力最大可能的边长。
输入输出样例
输入
2 10
6 5
5 6
输出
2
public class Main {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
int n = scan.nextInt();
int k = scan.nextInt();
int[][] nums = new int[n][2];
for (int i = 0; i < n; i++) {
nums[i][0]= scan.nextInt();
nums[i][1]= scan.nextInt();
}
int left = 1,right = 100000;
while (left < right) {
int mid = left + (right - left + 1) / 2;
int count = 0;
for (int i = 0; i < n; i++) {
count+=(nums[i][0]/mid) * (nums[i][1]/mid);
}
if (count < k) {
right = mid - 1;
}else left = mid;
}
System.out.println(left);
}
}
总结:暴力枚举题,枚举切的边长,当最后切出来的块数大于等于人数,就返回。我们可以优化为二分查找。
9、杨辉三角
杨辉三角也叫帕斯卡三角,在很多数量关系中可以看到,十分重要。
第0行: 1
第1行: 1 1
第2行: 1 2 1
第3行: 1 3 3 1
第4行: 1 4 6 4 1
....
两边的元素都是1, 中间的元素是左上角的元素与右上角的元素和。
我们约定,行号,列号都从 0 计数。所以: 第 6 行的第 2 个元素是 15,第 3 个元素是 20。
直观地看,需要开辟一个二维数组,其实一维数组也可以胜任。 如下程序就是用一维数组“腾挪”的解法。填空
import java.util.Scanner;
public class Main
{
// 杨辉三角形的第row行第col列
static long f(int row, int col){
if(row<2) return 1;
if(col==0) return 1;
if(col==row) return 1;
long[] a = new long[row+1];
a[0]=1;
a[1]=1;
int p = 2;
while(p<=row){
a[p] = 1;
for( _________________ ) a[q] = a[q] + a[q-1];
p++;
}
return a[col];
}
public static void main(String[] args){
System.out.println(f(6,2));
System.out.println(f(6,3));
System.out.println(f(40,20));
}
}
答案:int q=p-1;q>=1;q--
总结:从上面可以看出来while循环是循环第几行,里面的for是为了遍历行内的元素,根据题目提示现在这个就是之前的a[q]+a[q-1],所以每次就是遍历这个q,我们要逆序遍历,为了不影响到下一次遍历
10、Excel地址
Excel 单元格的地址表示很有趣,它使用字母来表示列号。
比如,
A 表示第 1 列,
B 表示第 2 列,
Z 表示第 26 列,
AA 表示第 27 列,
AB 表示第 28 列,
BA 表示第 53 列,
当然 Excel 的最大列号是有限度的,所以转换起来不难。
如果我们想把这种表示法一般化,可以把很大的数字转换为很长的字母序列呢?
本题目即是要求对输入的数字, 输出其对应的 Excel 地址表示方式。
输入描述
输入一个整数 nn,其范围 [1,2147483647]。
输出描述
输出 nn 对应的 Excel 地址表示方式。
输入输出样例
示例
输入
26
输出
Z
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int n=in.nextInt();
String str="";
for(int s;n!=0;n/=26){
if(n%26==0) {
n-=26;
s=26;
}else {
s=n%26;
}
str=(char)(s+64)+str;
}
System.out.print(str);
in.close();
}
}
总结:有点类似进制转换,循环每次都除26,除26前取余,然后记录余数,最后把他们字符串拼接起来,前面的余数在后面所以是str=(char)(s+64)+str; 其中如果除26==0就让s==26因为没有0这个对应的字母26就是z,然后n要减去26
11、日期问题
小明正在整理一批历史文献。这些历史文献中出现了很多日期。小明知道这些日期都在 1960 年 1 月 1 日至 2059 年 12 月 31 日。令小明头疼的是,这些日期采用的格式非常不统一,有采用年/月/日的,有采用月/日/年的,还有采用日/月/年的。
更加麻烦的是,年份也都省略了前两位,使得文献上的一个日期,存在很多可能的日期与其对应。
比如 02/03/04,可能是 2002 年 03 月 04 日、2004 年 02 月 03 日或 2004 年 03 月 02 日。
给出一个文献上的日期,你能帮助小明判断有哪些可能的日期对其对应吗?
输入描述
一个日期,格式是 "AA/BB/CCAA/BB/CC" (0 \leq A, B, C \leq 90≤A,B,C≤9)。
输出描述
输出若干个不相同的日期,每个日期一行,格式是 "yyyy-MM-ddyyyy−MM−dd"。多个日期按从早到晚排列。
输入输出样例
示例
输入
02/03/04
输出
2002-03-04
2004-02-03
2004-03-02
package saunfati;
import java.text.SimpleDateFormat;
import java.util.Scanner;
import java.util.TreeSet;
public class 日期问题 {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String temp = scanner.next();
String date[] = temp.split("/");
String y = date[0];
String m = date[1];
String d = date[2];
String a = (Integer.parseInt(y)<60?"20"+y:"19"+y)+"-"+m+"-"+d;
String b = (Integer.parseInt(d)<60?"20"+d:"19"+d)+"-"+y+"-"+m;
String c = (Integer.parseInt(d)<60?"20"+d:"19"+d)+"-"+m+"-"+y;
TreeSet<String> set = new TreeSet<String>();
if(f(a)) set.add(a);
if(f(b)) set.add(b);
if(f(c)) set.add(c);
for(Object object:set) {
System.out.println(object);
}
}
static boolean f(String date) {
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
format.setLenient(false);
try {
format.parse(date);
}catch(Exception e) {
return false;
}
return true;
}
}
总结:本地可以用TreeSet来做到去重和排序。而且可以用SimpleDateFormat的setLenient方法来判断日期是否有效的。