zoukankan      html  css  js  c++  java
  • hihocoder第220周-一道拧巴的题

    一、220周

    题目链接

    问题描述

    键盘上有N个数字按键,每个按键只能按一次,每次可以按下多个键,请输出所有可能的按键情况。
    输入一个整数N(N在1~8之间),输出全部的按键可能。例如:输入3,输出为

    1-2-3
    1-23
    1-3-2
    12-3
    123
    13-2
    2-1-3
    2-13
    2-3-1
    23-1
    3-1-2
    3-12
    3-2-1
    

    输出按照字符串大小从小到大输出。

    思路

    对于给定数组a,a中存放着备用数字,从a中分别取1,2,3,...len(a)个元素组成一组group。然后a-group=b,将b数组递归向后传递。

    Java里面的迭代器比较难受,写出来的代码也拧巴,这点非常考验代码能力,是一道非常不错的面试题。

    Python里面的生成器更简便。

    代码

    import sun.reflect.generics.tree.Tree;
    
    import java.util.*;
    import java.util.stream.Collectors;
    
    public class Main {
    TreeSet<String> a = new TreeSet<>();
    
    class SelectCount implements Iterator<String> {
        int[] a;
        int cnt;
        int[] p;
        boolean over = true;
    
        SelectCount(int[] a, int cnt) {
            this.a = a;
            this.cnt = cnt;
            p = new int[cnt];
            for (int i = 0; i < cnt; i++) {
                p[i] = i;
            }
        }
    
        @Override
        public boolean hasNext() {
            return over;
        }
    
        void move() {
            for (int i = cnt - 1; i >= 0; i--) {
                if (p[i] != a.length - cnt + i) {
                    p[i]++;
                    for (int j = i + 1; j < cnt; j++) {
                        p[j] = p[j - 1] + 1;
                    }
                    return;
                }
            }
            over = false;
        }
    
        @Override
        public String next() {
            String ans = Arrays.stream(p).map(x -> a[x]).mapToObj(x -> x + "").collect(Collectors.joining());
            move();
            return ans;
        }
    }
    
    void go(int[] a, LinkedList<String> l) {
    //    System.out.println(Arrays.stream(a).mapToObj(x -> x + "").collect(Collectors.joining()));
        if (a.length == 0) {
            this.a.add(l.stream().collect(Collectors.joining("-")));
            return;
        }
        for (int i = 1; i <= a.length; i++) {
            SelectCount sel = new SelectCount(a, i);
            while (sel.hasNext()) {
                String s = sel.next();
                int[] b = new int[a.length - i];
                int bi = 0;
                //a数组减去b数组
                for (int j = 0; j < a.length; j++) {
                    if (!s.contains(a[j] + "")) {
                        b[bi++] = a[j];
                    }
                }
                l.add(s);
                go(b, l);
                l.removeLast();
            }
        }
    }
    
    Main() {
        Scanner cin = new Scanner(System.in);
        int N = cin.nextInt();
        int[] a = new int[N];
        for (int i = 1; i <= N; i++) {
            a[i - 1] = i;
        }
        go(a, new LinkedList<>());
        for (String i : this.a) {
            System.out.println(i);
        }
    }
    
    public static void main(String[] args) {
        new Main();
    }
    }
    

    二、221周

    题目链接
    还是上面那样的题干,问题变成一道组合计数题,问一共有多少种按法。

    枚举第一次按下的情况,剩下的情况递归解决,递归时可以利用DP加速,不加速肯定超时。计算组合数时,必须使用杨辉三角,否则太慢。使用编程语言时,必须用C/C++,连Java都会超时,这个超时当然是运行效率了。

    #include<stdio.h>
    #include<iostream> 
    #include<stdlib.h>
    #include<string.h>
    using namespace std; 
    int mod = 1000000007;
    typedef long long ll;
    ll c[1007][1007];
    void init() {
    	memset(c, 0, sizeof(c));
    	for (int i = 0; i < 1007; i++)c[i][0] = 1;
    	c[0][0] = 1;
    	for (int i = 1; i < 1007; i++) {
    		for (int j = 1; j <= i; j++) {
    			c[i][j] = c[i - 1][j - 1] + c[i - 1][j];
    			c[i][j] %= mod;
    		}
    	} 
    }
    ll dp[1007];
    ll solve(int N) {
    	if (N == 1 || N == 0)return 1;
    	if (dp[N] != -1)return dp[N];
    	ll s = 0;
    	for (int i = 1; i <= N; i++) {
    		s += c[N][i]%mod * solve(N - i)%mod;
    		s %= mod;
    	}
    	dp[N] = s;
    	return s;
    }
    int main() {
    	int N;
    	cin >> N;
    	init(); 
    	memset(dp, -1, sizeof(dp));
    	cout << solve(N);
    	return 0;
    }
    
  • 相关阅读:
    Java基础-集合框架的学习大纲
    Java多线程并发学习-进阶大纲
    Spring学习大纲
    Netty学习大纲
    分布式学习大纲
    数据库学习大纲
    缓存学习大纲
    JVM-jvm学习大纲(0)
    多线程学习-基础(十三)(学习参考·网摘) ArrayBlockingQueue源代碼解析(base jdk 1.8)
    C#数字图像处理算法学习笔记(一)--C#图像处理的3中方法
  • 原文地址:https://www.cnblogs.com/weiyinfu/p/9677579.html
Copyright © 2011-2022 走看看