小红书20220904秋招-数据开发-笔记

题目1:镜像序列(找规律)

一个序列的生成方式如下:
序列生成需要一个基础序列A,这个序列由n个不大于100的数字组成,同时给定镜像复制次数n。
然后对于A进行m次镜像复制,例如序列A={1,2,3}
则一次镜像复制后得到的序列是{1,2,3,3,2,1)
两次镜像复制得到的序列是B=(1,2,3,3,2,1,1,2,3,3,2,1)。

现在给出你生成一个序列所需要的参数,请你计算该序列的第k位是多少。 输人描述 输入第一行包含三个整数n,m,k,含义如题所示。
(1<=n<=100,1<=m<=60,1<=k<=1e18,部分数据k<10000)
输入第二行包含n个正整数,每个正整数都不大于100,表示基础序列A。 数字间有空格隔开 输出仅包含一个正整数,即序列第k位的数字。

input:
3 3 10
1 2 3

# 输入
n, m, k = list(map(int, input().split()))
a = list(map(int, input().split()))
# 复杂度极高的解法:
# 用for循环生成
k = k - 1
for i in range(m):
	i += 1
	a = a + list(reversed(a)) #或者 a = a + a[::-1] 切片截取
print(a[k])

#用除余方法:
a = a + a[::-1]
k = k / (2*n) - 1
print(a[k])

题目2:加减数组元素使乘积为7(贪心或动态规划)

给定n个整数a1, a2, a3…an。每次操作可以选择其中一个数,并将这个数加上1或者减去1。
小红非常喜欢7这个数,他想知道至少需要多少次操作可以使这n个数的乘积为7?
输入描述
第一行输入一个正整数n,表示整数的个数。
第二行输入n个整数a1, a2, a3…an,其中ai表示第i个数。
输出描述
输出一个整数,表示将所有数的乘积变为7最少需要的操作次数。

input:
5
-6 0 2 -2 3
output:
6

# 贪心算法

# 一个元素 7
# 两个元素 7和1 ++ --
# 三个元素 7 1 1 +++ +--
# 贪心方法:先找最接近7或者-7的;再将其他值变为-1或1
# 输入
n = int(input())
A = list(map(int,input().split))
count = 0
neg = 0
if n > 1:
	# map函数 map(function,iterable) iterable一个或者多个序列
	# def f(x):
	#     return x*x
	# print(list(map(f, [1, 2, 3, 4, 5, 6, 7, 8, 9])))
	# str.split(str="", num=string.count(str)) num表示分隔次数,遇到num次分隔,后面的不管
	# 寻找list里距离7或者-7最近的值,取绝对值法对原来的list进行取值
	B = max(A, key = abs) #返回取绝对值后最大的值对应的原值
	# max函数里用key关键词引用一个函数,先对该list调用函数再取max,并且返回的是原来list的值
	# 字典里用key = a.get 表示a.get(item) 输出最大的值(item)对应的键(key)。否则在字典里的key中选最大值。
	A.remove(B) #将该数值从列表中去除
	if B>=0:
		count += abs(B-7)
	else:
		count += abs(B+7)
		# 负数要记录
		neg += 1
	# 对其他数取-1和1值,考虑如果有0,则可以不需要在意neg
	M = min(A, key = abs)
	# 将所有值调整为1或-1
	for i in A:
		# 把小于0的都调整为-1
		if i < 0 :
			count += abs(i + 1)
			neg += 1
		# 把大于等于0的都调整为1
		else:
			count += abs(i - 1)
	# 如果有0,不需要考虑neg,只要变为1或-1都可以
	if M != 0 && (neg / 2) != 0:
		count += 2
else:
	count = abs(7-B)
print(count)
//动态规划解法

public class solution {
    public void main(String[] args){
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int[] a = new int[n];
        for (int i = 0; i < n; i++) {
            a[i] = sc.nextInt();
        }
// 对每个元素都计算与7 -7 1 -1的距离,从0开始
        long dp7 = Math.abs(a[0] - 7); //与7的距离
        long dp_7 = Math.abs(a[0] + 7); //与-7的距离
        long dp1 = Math.abs(a[0] - 1); //与1的距离
        long dp_1 = Math.abs(a[0] + 1); //与-1的距离

// 遍历每个位置
        for (int i = 1; i < n; i++) {
            int v = a[i]; // 元素1
// 新加入的元素取什么值
// 整体结果为-7
            long newDp_7 =
                    Math.min(
                            Math.min(
                                    dp_7 + Math.abs(v - 1), //本次取1 原来取-7 得到-7
                                    dp_1 + Math.abs(v - 7) //本次取7 原来取-1 得到-7
                            ),
                            Math.min(
                                    dp1 + Math.abs(v + 7), //本次取-7 原来取1 得到-7
                                    dp7 + Math.abs(v + 1)
                            )
                    );
// 整体结果为7
            long newDp7 =
                    Math.min(
                            Math.min(
                                    dp_7 + Math.abs(v + 1),
                                    dp_1 + Math.abs(v + 7)
                            ),
                            Math.min(
                                    dp1 + Math.abs(v - 7),
                                    dp7 + Math.abs(v - 1)
                            )
                    );
// 整体结果为-1
            long newDp_1 =
                    Math.min(
                            dp_1 + Math.abs(v - 1),
                            dp1 + Math.abs(v + 1)
                    );
// 整体结果为1
            long newDp1 = 
                    Math.min(
                            dp_1 + Math.abs(v + 1),
                            dp1 + Math.abs(v - 1)
                    );
            dp_7 = newDp_7;
            dp_1 = newDp_1;
            dp1 = newDp1;
            dp7 = newDp7;
        }
        System.out.println(dp7);
    }
}

题目3:最小过路费(图)

小明的旅途中需要经过一个国家。这个国家有n个城市,编号为1到n。小明会从1号城市进入,
目标是从n号城市出去(即要从1号城市到达n号城市)。有m条双向道路连接这n个城市,每条道路的长度都是1,并且都有一个过路费(是[1,100000]之间的整数)。
当小明在一号城市时他可以预先花费X的费用办一张特权卡,他可以获得所有过路费不超过X的道路的通行权(而其他道路无法通过)。
小明一天最多只能走k长度的路,他想知道如果他想在一天之内从1号城市到n号城市,他最少需要花费多少来办特权卡
即求X的最小值?
第一行是3个整数n,m,k,分别表示城市数,道路数和小明一天最多能走的长度
第二行m个整数,分别为u1, u2…um,分别表示第i条道路的一个端点。
第三行m个整数,分别为v1, v2…vm,分别表示第i条道路的另一个端点。
第四行m个整数,分别为w1, w2…wm,分别表示第条道路的过路费
数字间两两有空格隔开。数据保证一定存在解
输出描述
一行一个整数,表示X的最小值

input:
5 6 3
1 1 2 3 3 4
2 5 3 4 5 5
1 3 1 2 1 1
output:
1

# 读入图
n, m, k = list(map(int, input().split()))
u = list(map(int, input().split()))
v = list(map(int, input().split()))
w = list(map(int, input().split()))

# 用字典构造图,用defaultdict构建邻接表
from clollections import defaultdict
g  = defaultdict(dict) # 内置一个dict

# 图的构造方法,可以用边和点的关系,用权重标识,否则为0
for i in range(m):
	g[u[i]][v[i]] = w[i] # g[1][2] = 1,g[1][5] = 3,g[2][3] = 1
	g[v[i]][u[i]] = w[i] 
# 结果:
# g[1] = {2:1,5:3}
# g[5] = {1:3,3:1,4:1}

# 遍历法 记录路径,如果路径超过k,就跳过,广度优先搜索法,需要考虑visited
def check(y):
	q = deque([1,0]) # 当前点为1,当前路径为0
	visited = [False] * (n+1) # 已访问过就为true 也可以用set实现 visited = set() xx in visited
	visited[1] = True
	while q:
		cnt,step = q.popleft()
		if cnt == n:
			return True
		for nxt , v in g[cnt].items(): # 取该点的邻居及其权重
			# 需要满足权重小于等于检查的值y 且 当前的路径加上1还能小于等于k 且 未参观该路径
			if v <= y and step + 1 <= k and not visited[nxt]# 把该元素放入q中,进入下一次遍历
				q.append([nxt,step+1])
				visited[nxt] = True
	return false

#用二分法实现寻找最小值
l = 1
r = max(w)
while l < r:
	mid = l+r >> 1
	if check(mid): # 说明mid可以通过,取左边
		r = mid
	else :
		l = mid + 1
print(r)

同样的实现方法用java写一遍

class Solution{
	private static final int N = 100010, M = 400010;
	private static Queue<int[]> q = new ArrayDeque<>(N);
	private static int n,m,k;
	private static int[] u = new int[M],v = new int[M],w = new int[M];
	private static int[][] edge;

	public static void main(String[] args){
		Scanner sc = new Scanner(System.in);
		sc1 = sc.nextLine().split();
		int n = Integer.parseInt(sc1[0]);
		int m = Integer.parseInt(sc1[1]);
		int k = Integer.parseInt(sc1[2]);

		edge = new int[n+1][n+1];


		// 存储图
		sc2 = sc.nextLine().split();
		sc3 = sc.nextLine().split();
		sc4 = sc.nextLine().split();

		maxW = Integer.parseInt(sc4[0]);

		for(int j = 0; j < m; j++){
			// 初始化图为邻居矩阵存储权值
			edge[Integer.parseInt(sc2[j])][Integer.parseInt(sc3[j])] = Integer.parseInt(sc4[j]);
			if (maxW < Integer.parseInt(sc4[j])){
				maxW = Integer.parseInt(sc4[j]);
			}
		}
		
		// 用二分法找最小值,如果mid不能通过,则在右侧,否则在左侧
		int l = 1,r = maxW;
		// 当mid不能通过时,选右侧
		while(l < r){
			int mid = (l+r)/2; // 用>>符号 l + r >> 1 运算更快
			if(!bfs(mid)){
			l = mid + 1;
			}
			else{
				r = mid;
			}
		}
		System.out.print(r);
	}

// 判断用x的费用是否通路
	public static boolean bfs(int y){
		// 重新寻找通路
		q.clear();
		// 添加初始点1 和 初始路径距离0
		q.add(new int[] {1,0});
		HashSet<int> s = new HashSet<int>(); 
		while (!q.isEmpty()){
			int[] cur = q.poll();
			int u = cur[0]; // 当前点
			int step = cur[1];
			s.add(u);
			if (u == n): return true; // 若当前点为n则返回可以,否则遍历
			for(int i = 1;i < n+1;i++){
				if (edge[u][i] is null)  continue;
				if (i in s) continue;
				if (edge[u][i] > y || step + 1 > k) continue;
				else {
					q.add(new int[]{i,step + 1});
					s.add(i);
				}
			}

		}
		return false;

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值