记牛客2018真题笔试刷(二)

目录

操作序列(思考,网易)

疯狂序列(思考,网易)

循环数比较(利用语言特性,爱奇艺)

回文素数(回文判断,素数判断,爱奇艺)

红和绿(简易动态规划,统计次数,爱奇艺)


操作序列(思考,网易)

题目描述

小易有一个长度为n的整数序列,a_1,...,a_n。然后考虑在一个空序列b上进行n次以下操作:
1、将a_i放入b序列的末尾
2、逆置b序列
小易需要你计算输出操作n次之后的b序列。

输入描述:

输入包括两行,第一行包括一个整数n(2 ≤ n ≤ 2*10^5),即序列的长度。
第二行包括n个整数a_i(1 ≤ a_i ≤ 10^9),即序列a中的每个整数,以空格分割。

输出描述:

在一行中输出操作n次之后的b序列,以空格分割,行末无空格。

示例1

输入

4
1 2 3 4

输出

4 2 1 3

思路

思路就是按题目中所叙述的,每次先填入到b,再把b序列增提逆置。但这样肯定超时,要求时间复杂度O(n)

正确的思路是找规律,

当n为偶数时,先从后向前从最后一个数,以间隔为2,将读取到的数字插入到b中。然后,再将剩下的元素按原来顺序插入到b中。

当n为奇数时, 先从后向前从最后一个数,以间隔为2,将读取到的数字插入到b中。然后,再将剩下的元素按原来顺序插入到b中

怎么得到的呢?我也没分析出来。估计是找规律吧

还需要注意的是:

1.列表元素从后向前排列: a[::-1]

2.列表元素分区别遍历:a[start:end:step]

人家的code

# -*- coding:utf-8 -*-

n=int(raw_input().strip())
a=raw_input().strip().split()
b=[]
"""
for i in range(n):
    b.append(a[i])
    b=b[::-1]
    
a = [1 2 3 4 5]
print(a[::-1]) ### 取从后向前(相反)的元素
[ 5 4 3 2 1 ]
 
print(a[2::-1]) ### 取从下标为2的元素翻转读取
[ 3 2 1 ]


list[start:end:step]
start:起始位置
end:结束位置
step:步长


其最后输出的序列分两部分,前一半从最后一个数开始以2为步长递减;后一半根据整数
个数的奇偶,分别从第二个或第一个数开始以2为步长递增。找到了这个规律,O(n)的算
法就很容易写出来了:
"""
if n%2==0:
    b.extend(a[1::2][::-1])
    b.extend(a[::2])
else:
    b.extend(a[::2][::-1])
    b.extend(a[1::2])
print ' '.join(b)

疯狂序列(思考,网易)

题目描述

小易老师是非常严厉的,它会要求所有学生在进入教室前都排成一列,并且他要求学生按照身高不递减的顺序排列。有一次,n个学生在列队的时候,小易老师正好去卫生间了。学生们终于有机会反击了,于是学生们决定来一次疯狂的队列,他们定义一个队列的疯狂值为每对相邻排列学生身高差的绝对值总和。由于按照身高顺序排列的队列的疯狂值是最小的,他们当然决定按照疯狂值最大的顺序来进行列队。现在给出n个学生的身高,请计算出这些学生列队的最大可能的疯狂值。小易老师回来一定会气得半死。

输入描述:

输入包括两行,第一行一个整数n(1 ≤ n ≤ 50),表示学生的人数
第二行为n个整数h[i](1 ≤ h[i] ≤ 1000),表示每个学生的身高

输出描述:

输出一个整数,表示n个学生列队可以获得的最大的疯狂值。

如样例所示: 
当队列排列顺序是: 25-10-40-5-25, 身高差绝对值的总和为15+30+35+20=100。
这是最大的疯狂值了。

示例1

输入

5
5 10 25 40 25

输出

100

思路

我的思路是先按升序排好序列,然后,每次从首尾各取两个元素填入到新的序列中,并计算疯狂值,并累加,最后,得到的就是最终结果。如果偶数个元素,就如上所说;如果是奇数个,把最后一个单个元素放到序列首位。

对比正确思路,发现和我的大方向一致,

需要借鉴的地方是,

1.人家是求出一个mid值来,然后,先把mid给放到crazy_seq中,这样就保证了当奇数个时,最后的那个单个元素放到了首位,那偶数的时候呢?我苦思了好久,一直觉得正确的程序错了,没考虑偶数的情况,其实不然,人家的程序很巧妙的把这种情况中和了。比如带入“5, 10, 25, 40”,正确的是:“10,40, 5, 25”最大,疯狂值为85,按下列程序排完序后“25,5,40,10,25”看起来后者把四个数排了两次,但最后计算疯狂值的时候,其实是没有用到最后那一个数的,整个序列长度为4,那么计算的时候只计算了前四个数的差值,最后一个没算,等同于排列序列为“25, 5, 40 ,10”,疯狂值等于85。

真真很是巧妙!

2.用mid的方法,首位开始循环,但实际只循环了一半的空间。可借鉴!

3.填入crazy_seq的元素先后顺序也是有讲究的,先填入小的,再填入大的,最后,把前半个序列中最大的(mid)给放到最开头,和最小的相连,保证疯狂值最大。

4.最后通过length成功的将偶数列和奇数列统一到了一块儿,这种思路非常巧妙!

5.整个序列可以这样实现,是利用了length,和实际序列排列下标是从0开始的这一条件。充分利用!

人家的code

length = input()
s = raw_input()
s = map(int, s.split(" "))
s.sort()
mid = length/2
crazy_seq = []
crazy_seq.append(s[mid])
for i in range(mid):
    crazy_seq.append(s[i])
    crazy_seq.append(s[length-1-i])
sum = 0
for i in range(1, length):
    cha = abs(crazy_seq[i]-crazy_seq[i-1])
    sum += cha
print sum

 

循环数比较(利用语言特性,爱奇艺)

题目描述

对于任意两个正整数x和k,我们定义repeat(x, k)为将x重复写k次形成的数,例如repeat(1234, 3) = 123412341234,repeat(20,2) = 2020.
牛牛现在给出4个整数x1, k1, x2, k2, 其中v1 = (x1, k1), v2 = (x2, k2),请你来比较v1和v2的大小。

输入描述:

输入包括一行,一行中有4个正整数x1, k1, x2, k2(1 ≤ x1,x2 ≤ 10^9, 1 ≤ k1,k2 ≤ 50),以空格分割

输出描述:

如果v1小于v2输出"Less",v1等于v2输出"Equal",v1大于v2输出"Greater".

示例1

输入

1010 3 101010 2

输出

Equal

思路

我的思路,既然是比大小,先计算位数,如果位数都不一样,肯定是位数大的数比较大,接着位数相等的情况下,那只要高位相比分出大小,后面位就不需要比较了,直接就是高位大的数就大,只有当高位相等时,才需要比较后面的位数。

故,先求出v1,v2,如果位数相等,再从高位到低位逐个比较大小。

看了人家的思路之后,发现自己还是太年轻了,把v1,v2求出来后,直接转换成数字,交给编译器作比较就行了。

人家的code

x1,k1,x2,k2=map(int,raw_input().split())
s1=str(x1)*k1
s2=str(x2)*k2
if int(s1)<int(s2):
    print 'Less'
elif int(s1)>int(s2):
    print 'Greater'
else:
    print 'Equal'

 

回文素数(回文判断,素数判断,爱奇艺)

题目描述

如果一个整数只能被1和自己整除,就称这个数是素数。
如果一个数正着反着都是一样,就称为这个数是回文数。例如:6, 66, 606, 6666
如果一个数字既是素数也是回文数,就称这个数是回文素数
牛牛现在给定一个区间[L, R],希望你能求出在这个区间内有多少个回文素数。

输入描述:

输入包括一行,一行中有两个整数(1 ≤ L ≤ R ≤ 1000)

输出描述:

输出一个整数,表示区间内回文素数个数。

示例1

输入

100 150

输出

2

思路

我的思路是判断素数和回文数,它们肯定都有各自判断的条件,回文数就是分成偶数长和奇数长开始首尾遍历,如果大小都一直一致,就说明是回文数,素数的话,倒是没想到有什么好的方法来判断。

看人家的思路

1.判断回文的时候,非常简洁!直接把带比较的对象,反排一下,也算是利用了python的特性,然后比较 str(m) == str(m)[::-1],可借鉴!

2.判断素数的时候,先设置一个边界条件,小于1的话,就不用判断了,肯定不是。再切入正题,sqrt() 方法返回数字x的平方根,

从2开始到该数的平分根,如果有可以整除的,就不是,如果没有,就是,这个判断素数的方式也要记住,可借鉴!!

另外,找平方根作截点,是乘法中的找mid值了!

人家的code

import math
def isprime(n):
    if n<=1:
        return False
    for i in range(2,int(math.sqrt(n))+1):
        if n%i==0:
            return False
    return True
def ishuiwen(m):
    if str(m)==str(m)[::-1]:
        return True
    return False
if __name__=='__main__':
    line=raw_input()
    a,b=int(line.split(' ')[0]),int(line.split(' ')[1])
    ans=0
    for i in range(a,b+1):
        if isprime(i) and ishuiwen(i):
            ans+=1
    print(ans)

红和绿(简易动态规划,统计次数,爱奇艺)

题目描述

牛牛有一些排成一行的正方形。每个正方形已经被染成红色或者绿色。牛牛现在可以选择任意一个正方形然后用这两种颜色的任意一种进行染色,这个正方形的颜色将会被覆盖。牛牛的目标是在完成染色之后,每个红色R都比每个绿色G距离最左侧近。牛牛想知道他最少需要涂染几个正方形。
如样例所示: s = RGRGR
我们涂染之后变成RRRGG满足要求了,涂染的个数为2,没有比这个更好的涂染方案。

输入描述:

输入包括一个字符串s,字符串s长度length(1 ≤ length ≤ 50),其中只包括'R'或者'G',分别表示红色和绿色。

输出描述:

输出一个整数,表示牛牛最少需要涂染的正方形数量

示例1

输入

RGRGR

输出

2

思路

我的思路是先找中间值,左侧的绿色全涂红,右侧的红色全涂绿。但我也这样有点问题。

人家的思路貌似是借鉴了动态规划的思想,设置一个当前位置从左侧起始位置进行遍历,统计从左侧起始到当前位置中绿色块儿的数量和从当前位置到右侧末尾中红色块儿的数量的加和,最后,取最小就可以了。

这个思路好啊!直接就一次遍历就可以了!因为这个问题不需要排序,只统计次数就行了,厉害!可借鉴!

人家的code

s=raw_input().split()
s=s[0]
N = []
for i in range(len(s)+1):
    num = s[:i].count('G') + s[i:].count('R')
    N.append(num)

print min(N)

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值