2022腾讯前端实习生笔试题与部分详细题解

前言与详细题目和个人题解

4月24晚举行的笔试,我做得不是很好,心态有点坏(第一次参加企业笔试紧张、紧绷),而且刚好有盲区被考到了。经历之后心态提升了,也知道了自己不足,现在来一起学习吧:P
试题题目如下,时间2个小时,5道编程题,我先分析其中2道,尽力做到透彻了然。

  1. 填入空缺代码实现放大镜效果(设计题)
  2. 循环链表的最小字典序
  3. 股票买入卖出收益最大化
  4. 根据给定深度实现数组的扁平化
  5. 拖动排序

详情可以看👉 牛客网2022腾讯前端实习生笔试分享贴


一、根据给定深度实现数组的扁平化

给定一个数组和深度n 要求将数组扁平至n层
如输入 [1, 2, 3, [4] ], 1
则输出 [ 1, 2, 3, 4 ]

[ 1, 2, [3, [4, [5] ] ] ], 2
[1, 2, 3, 4, [5]]

[1, [2]], 1
[1, 2]

[1, [2]], 2
[1, 2]

实现的功能与Array.prototype.flat()相似,但是笔试用不了。
一个简单的实现思路: 遍历数组中的每一项元素,因为要实现扁平化数组,但是又不确定类型为数组的元素里还有没有子数组,例如[ 1, [2, [3]] ],而扁平一次就成为[ 1, 2, [3] ],再扁平一次就成为[ 1, 2, 3 ],扁平就是多层嵌套数组每一项都降低层数。基于此,容易联想到递归思想

		// 原数组
		const arr = [ 1, 2, [3, [4, [5] ] ] ];
		// 自设定深度
		// const deep = 3;
		const deep = 2;
		// 结果数组
		let result= [];
		
		// 思想: 提取原数组每一项元素,然后判断元素为数字或数组,数字则推入暂存数组,数组则递归,判断推入
		const myFlat = (arrInput, curDeep) => {
			// 退出
			if(curDeep==0){
				return arrInput;
			}
			// 存放本层结果
			let tempArr = [];
			for(let i=0;i<arrInput.length;i++){
				let item = arrInput[i];
				if(Array.isArray(item)){
					// 向下递归,结果层层返回
					let returnArr = myFlat(item,curDeep-1)
					tempArr = tempArr.concat(returnArr);
				} else {
					tempArr.push(item);
				}
			}
			return tempArr;
		};
		result = myFlat(arr, deep);
		console.log('DEEP: ',deep);
		console.log('RESULT: ',result);
		console.log('JSON_RESULT: ',JSON.stringify(result));

测试结果↓
深度为2
深度为1

更新: 可以考虑使用Array自带的concat方法与ES6+的扩展运算符…,该方法合并双方参数或数组返回一个新数组,它的作用之一是可以合并嵌套数组而且恰恰是合并的双方各取出一层嵌套,如[[1]].concat([2, [3]])=[[1], 2, [3]]。而扩展运算符对于数组的作用为切割数组每一项,成为以逗号分隔的参数,详细解释请看代码
所以现在更快捷的解法: 只需要对原数组自身调用n次concat(…arr)方法即可!

		function useConcatToFlatten(arr, curDeep){
			for(let i=0;i<curDeep;i++){
				// 1. concat是合并返回一个新的
				// 2. ...arr的作用等同于切割每一项元素成为独立参数,以逗号分开,控制台输出时不显示逗号
				// 3. [].concat(...arr) = [].concat(n1,n2,n3...)
				// 4. concat又可以合并嵌套数组,去掉每一项元素的一层嵌套,如果是[].concat(1, [2]) -> [[], 1, [2]] -> [1, 2]
				// 5. arr = [].concat(...arr) 这种写法可以更新覆盖掉arr原本的结果,再走下一步运算。
				arr = [].concat(...arr);// 如果是arr而非...arr,则不是切割元素,每项独立提供而是提供整块数组 n1,n2,n3 !== [n1,n2,n3]
				// console.log(...arr);// 这里可以自行查看
			}
			return arr;
		}
		let res2 = useConcatToFlatten([ 1, 2, [3, [4, [5] ] ] ], 2);
		console.log('JSON_RESULT2: ',JSON.stringify(res2));

二、股票买入卖出收益最大化

题目描述:
小Q的最大总资产
题目:
现在有一个长度为n的价格数组a,表示某只股票每天的价格,你每天最多买入或卖出该只股票的1手股票,买入或者卖出没有手续费,
且卖出股票前必须手里已经有股票才能卖出,但是持有的股票数目不受限制,并且初始资金为m元,
你在任意时刻都不能进行透支,所以你的资金必须始终大于等于 0 。
请问你在n天结束之后,拥有最大的总资产是多少?(总资产:股票数目*股票价格+现金)
输入两行,第一行是交易天数和初始金额,第二行是每天的股价。
6 2
2 3 1 1 1 2
输出:
6
个人理解:首先是样例的输出6,因为是2(初)-2+3-1-1-1=3,此时有3手股票,最后一天结束后抛出,按最后一天的股价2元,即2*3=6,整个周期最大收益是6元。

这题还是蛮有挑战性的,我打算好好琢磨一下,先自设简单样例,画画图过过想法吧。
3 5 / 1 1 2 肉眼判断最优解是:5-1-1=3,此时剩3元持2股,①最后一天卖出1股,剩5元1股,结算时总资产是5+1*2=7。②最后一天不卖,剩3元2股,结算时是3+2*2=7。③三天都买,总资产为1+3*2=7元。

伪流程图
伪流程图
如果用DFS也是可以做出来的,但是当数据量越大,整个时间开销会更大,近似O(2*3^n)。那么有别的思路吗,观察发现每一天结束,面临的选择无非是买、卖、不作为,做出选择后的经济情况又和昨天的经济息息相关,我今天卖了1股,我现在拥有j股,身上的钱 == 我昨天结束拥有j+1股的钱+今天股价。而我今天买了1股,现在有j股,身上的钱 == 我昨天结束拥有j-1股的钱-今天股价。我今天什么也没干,身上还是j股m钱 == 我昨天结束拥有j股m钱的状态。即第i天结束,我手上有j手股票,最多有3种原因,要么是第i-1天时我有j+1手股票,今天卖了1份;要么是第i-1天就有j手股票,而今天什么也不做;要么是第i-1天我有j-1手股票,今天买了1手,在这3种情况中取最大值,DP也就呼之欲出了。
我的DP代码(自测几组数据都ok)

#include<iostream>
#include<vector>
#include<cmath>
using namespace std;

int main() {
    // 股票交易天数  初始金额
    int days=0,start=0;
    
    // 输入
    cin >> days >> start;
    // 股票数组输入
    vector<int>stock(days, 0);
    for (int i = 0;i<days;i++) {
        cin >> stock[i];
    }
    // dp[i][j] i为第i天结束后 j为手上持有的股票数 值为当天结束剩余的现金 每个值初始化为-10000
    vector<vector<int> >dp(days, vector<int>(days, -10000));
    // 第一天的预处理 不买股票 和 可买股票 两种情况
    dp[0][0] = start;
    // 够钱买
    if (start >= stock[0]) {
        dp[0][1] = start - stock[0];
    }
    // 从第二天开始 i=1
    for (int i = 1;i<days;i++) {
        for (int j = 0;j<days;j++) {
            // 三种情况: 买、卖、不作为,不同j值下各自取最优值
            // 默认情况是不作为 继承昨天的状态
            dp[i][j] = dp[i - 1][j];
            // 当能买今天的股票的时候,才会解锁"买"的选项(昨天股票数+今天买的)
            if (j>0 && stock[i] <= dp[i - 1][j - 1]) {
                dp[i][j] = max(dp[i][j], dp[i - 1][j - 1] - stock[i]);
            }
            // 当昨天有股票卖的时候 解锁"卖"的选项(昨天持有的股票数-今天卖的)
            if (j+1<days){
                dp[i][j] = max(dp[i][j], dp[i - 1][j + 1] + stock[i]);
            }
        }
    }
    // 答案
    int res = 0;
    // 最优解 在最后一层,即最后一天结束后遍历取现金+股价*股票
    for (int i = 0;i < days;i++) {
        int value = 0;
        int finalStockValue = stock[days-1];
        int money = dp[days-1][i];
        // 当没有股票的时候
        if (dp[days - 1][i] != -1 && i == 0) {
            value = money;
            if (value > res) res = value;
        }
        // 有股票时
        else if (dp[days - 1][i] != -1 && i != 0) {
            value = money + i * finalStockValue;
            if (value > res) res = value;
        }
    }
    cout << res;
    return 0;
}

欢迎交流和指正

自感愚钝,上述两题解法是我的个人想法,如果您看到哪里有误或不足之处,或是有疑问的地方,欢迎私信或者留言指出呀,一起交流进步。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值