首页 > 试题广场 >

给定正整数n(n 100000),找到最小的由0,1组成

[问答题]

给定正整数n(n < 100000),找到最小的由0,1组成的十进制正整数m,满足m = k * n, k为正整数。输入n,输出最小的正整数m,若不存在,则输出-1. (和两个子序列的题组合)例如:输入:
2输出10,输入3输出111,输入18输出1111111110。可以使用标准的数据结构list, set, map, que,样例简单解释。

n=2, m=10 =5*n
n = 3 m =111 = 37 * n
n = 18 m = 1111111110 = 61728395 * n 
可以将所有的可能表示为一个序列
设vec[0] = 0
vec[i] = vec[i/2] *10 + i % 2
于是就是
0 1 10 11 100 101 110 111 。。
直到找到可以整除的数为止
发表于 2019-07-25 22:57:13 回复(0)
def is_suitable(m):
    # m是否满足有1 0 组成
    for digit in m:
        if digit != '1' and digit != '0':
            return False
    return True

def is_repeat(n, tmp_k):
    """
    如果每次要往前填的数字序列重复超过2次则必然存在死循环
    """
    end_num_list = []
    while tmp_k > 0:
        tmp = tmp_k % 10
        end_num_list.insert(0, tmp * n % 10)
        tmp_k //= 10
    len_num = len(end_num_list)
    if len_num < 2:
        return False
    i = len_num - 1
    while i > 1:
        mid = i // 2
        if(end_num_list[0:mid+1] == end_num_list[mid+1:i+1]):
            return i
        i -= 1
    return False

def tests(n, multi_dict, tmp_k, min_k=None):
    """
    基于树的深度的遍历
    如果这个节点不可取就回溯上一个节点 
    不可取情况:
    1.这个节点构成的值大于目前存在的min_k 此时返回min_k就是k最小情况; 
    2.这个节点构成的k存在死循环  返回造成循环的长度的负数作为标记 直到回溯到不能造成循环的节点
    
    最后在所有树里面选一个结果最小的k
    eg:
    n = 7 -> {7: [1], 4: [2], 1: [3], 8: [4], 5: [5], 2: [6], 9: [7], 6: [8], 3: [9]}
                      3 ( n=7只有一棵树)
            /                 \
           4                     7
         /   \                /    \
        1     4              5      8
       /     / \           /   \   /  \
     [1001] 1   4         8     1 ..  ..
           /     \       / \   / \
     [10101‬] [repeat]   2   5 .. ..
                       /   / \
                  [repeat] .. ..
    
    """
    m = n*tmp_k
    str_m = list(str(m))
    str_tmp_k = str(tmp_k)
    if is_suitable(str_m[0:len(str_m)-len(str_tmp_k)]):  # 如果m排除k长度必然满足条件部分仍满足条件 说明已经找到
        return tmp_k
    end_num = (10 - (tmp_k * n) // (10 ** len(str_tmp_k))) % 10
    repeat_len = is_repeat(n, tmp_k)
    if repeat_len > 0:  # 判断重复  如果一直循环 不可能有解
        return  - repeat_len
    j_list = []
    if end_num in multi_dict:
        j_list.extend(multi_dict[end_num])
    if end_num + 1 in multi_dict:
        j_list.extend(multi_dict[end_num+1])
    if not j_list:
        return False
    min_result = False
    for j in j_list:
        next_tmp_k = tmp_k + j * 10 ** len(str_tmp_k)
        if min_k and next_tmp_k // min_k > 0:  # 如果min_k存在 但目前要求的tmp_k比min_k大就没必要继续向下查询 直接返回min_k即可
            return min_k
        if min_result:
            result = tests(n, multi_dict, next_tmp_k, min_result)
        else:
            result = tests(n, multi_dict, next_tmp_k)
        if result < 0:  # 小于零表示选这个j会造成死循环  result的绝对值表示k数字中造成死循环的长度
            result += 1
            if result == 0:    # 这个j不被纳入考虑 如果j_list里还有存在的j就选下一个 没有就返回min_result
                continue
            return result
        if not min_result or (result and min_result > result):
            min_result =  result
    return min_result

if __name__ == '__main__':
    multi_dict = {}
    for i in range(1,10):
        tmp = i * n % 10
        if tmp not in multi_dict:
            multi_dict[tmp] = []
        multi_dict[tmp].append(i)
    j_list = []
    if 0 in multi_dict:
        j_list.extend(multi_dict[0])
    if 1 in multi_dict:
        j_list.extend(multi_dict[1])
    min_result = None
    for  j in j_list:
        result = tests(n, multi_dict, j)
        if result and (min_result is None or min_result > result):
            min_result = result
    if min_result:
        print(min_result*n)
    print(-1)  # 没有符合要求的

发表于 2019-08-20 11:26:56 回复(0)
利用树的层次遍历
public static long find(long k) {
		Queue<String> qu=new LinkedList<>();
		qu.add("1");
		long t=-1;
		long limit=k*100000;
		String s;
		while(!qu.isEmpty()) {
			s=qu.remove();
			t=Long.parseLong(s);
			if(t%k==0) {
				break;
			}
			if(t>=limit) {
				t=-1;
				break;
			}
			qu.add(s+"0");
			qu.add(s+"1");
		}
		
		return t;
	}


发表于 2020-03-14 11:29:07 回复(0)