【网易】瞌睡兴趣点总和
- 知识点:滑动窗口,动态规划
题目地址
//总体思路很简单,清醒时的兴趣点总和并不受影响,因此将最终结果分为两部分计算:
//1.清醒时总和,是不用更新的常量
//2.用一个长度为k的窗口在数组上滑动,计算窗口内睡着时的兴趣点总和,这一步可以用动态规划来做,
//最终算法时间复杂度为o(n),空间复杂度为o(n).
#include <iostream>
#include <algorithm>
using namespace std;
int main()
{
int n, k;
cin >> n >> k;
// n 代表课堂总时间,k代表叫醒一次的清醒时间
int score[n]; //存储每分钟兴趣值
bool sleep[n]; // 存储每分钟清醒状态
//读取数据
for (int i = 0; i < n; i++)
{
cin >> score[i];
}
for (int i = 0; i < n; i++)
{
cin >> sleep[i];
}
int res = 0;
int zeroMax = 0;
int dp[n];
for (int i = 0; i < n; i++)
{
if (sleep[i] == 1)
res += score[i]; //此循环中res存储所有清醒状态时的兴趣点之和
if (i < k && sleep[i] == 0)
zeroMax += score[i]; //次循环zeroMax存储dp的初始化值,代表0 - k分钟范围内,睡着时的兴趣点之和
}
dp[k-1] = zeroMax; // 初始化dp数组,dp[i]代表(i-k + 1)- i分钟范围内睡着时的兴趣点总和
for (int i = k; i < n; i++)
{
int leftEnd = sleep[i-k] == 1? 0: score[i-k];
int rightEnd = sleep[i] == 1? 0: score[i];
int curScore = dp[i-1] + rightEnd - leftEnd;
dp[i] = curScore;
zeroMax =std::max(curScore, zeroMax); //更新最大值
}
res += zeroMax;
cout << res << endl;
}
#【网易】丰收
题目地址
知识点:二分查找
#include <iostream>
#include <algorithm>
using namespace std;
int main()
{
int nHeap;
int mQ;
cin >> nHeap;
int sum[nHeap+1];
sum[0] = 0;
//初始化求和数组,sum[i]表示第1-i堆的苹果总数
int num;
for (int i = 1; i <= nHeap; i++)
{
cin >> num;
sum[i] = sum[i-1] + num;
//cout << sum[i] << endl;
}
cin >> mQ;
int q;
for (int i = 0; i < mQ; i++)
{
cin >> q;
//cout << q << endl;
//二分查找,要查找sum数组中比查询点大的最小的元素
int left = 0;
int right = nHeap;
while (left < right)
{
int mid = (right + left)>>1;
if (sum[mid] < q)
{
left = mid + 1; //
}
else
{
right = mid;
}
}
cout << left << endl;
}
}
#【网易】塔
链接:https://www.nowcoder.com/questionTerminal/54868056c5664586b121d9098d008719?toCommentId=5237172&ran=943
来源:牛客网
知识点:堆排序,排序算法
- 我的思路是用堆排序,每次从最大堆搬一个到最小堆,终止条件是,操作数op >= k或者最高塔和最低塔高度差小于等于1.时间复杂度O(klogn),空间复杂度O(n)
也可以不用堆得到最大最小值,每次循环对塔的高度排序,时间复杂度o(knlogn),经过测试,虽然理论上排序法比堆排序更慢,但实际运行却更快。
import java.util.*;
public class Main {
public int n;
public int k;
PriorityQueue<Tower> minHeap;
PriorityQueue<Tower> maxHeap;
public Main()
{
Scanner sc = new Scanner(System.in);
n = sc.nextInt();
k = sc.nextInt();
minHeap = new PriorityQueue<>(n, new Comparator<Tower>(){
@Override
public int compare(Tower a, Tower b)
{
return a.height - b.height;
}
});
maxHeap = new PriorityQueue<>(n, new Comparator<Tower>(){
@Override
public int compare(Tower a, Tower b)
{
return b.height - a.height;
}
});
for (int i = 1; i <= n; i++)
{
int height = sc.nextInt();
Tower t = new Tower(height, i);
minHeap.add(t);
maxHeap.add(t);
}
}
public class Tower {
public int height;
public int index;
public Tower(int h, int i)
{
height = h;
index = i;
}
}
public void solution()
{
int maxDiff = maxHeap.peek().height - minHeap.peek().height;
List<int[]> records = new ArrayList<int[]>();
int op = 0;
while (minHeap.peek().height != maxHeap.peek().height && op < k)
{
Tower high = maxHeap.poll();
Tower low = minHeap.poll();
int[] rec = {high.index, low.index};
records.add(rec);
high.height--;
low.height++;
op++;
maxHeap.add(high);
minHeap.add(low);
maxDiff = maxHeap.peek().height - minHeap.peek().height;
}
System.out.print(maxDiff + " ");
System.out.println(op);
for (int[] rec: records)
{
System.out.print(rec[0] + " ");
System.out.println(rec[1]);
}
}
public static void main(String[] args)
{
Main m = new Main();
m.solution();
}
}
#【网易】+*()表达式求值
题目地址
知识点:动态规划
思路:题目只涉及三个数,可以暴力穷举,扩展到n个数穷举就不现实了
动态规划的思路是,dp[i][j]存储了从i到j中最大的数,更新公式为:
对于[i, j)之间的任意一个数k,dp[i][j] = max(dp[i][k] * dp[k+1][j], dp[i][k] + dp[k+1][j], dp[i][j])
import java.util.*;
public class Main {
public static void main(String[] args)
{
Scanner sc = new Scanner(System.in);
int[] nums = new int[3];
for (int i = 0; i < 3; i++)
{
nums[i] = sc.nextInt();
}
int N = nums.length;
int[][] dp = new int[N][N];
for (int i = N-1; i >= 0; i--)
{
for (int j = i; j < N; j++)
{
if (i == j)
dp[i][j] = nums[i];
else
{
for (int k = i; k < j; k++)
{
dp[i][j] = Math.max(dp[i][k] + dp[k+1][j], Math.max(dp[i][k] * dp[k+1][j], dp[i][j]));
}
}
}
}
System.out.println(dp[0][N-1]);
}
}
#【网易】字典
问题地址
- 知识点:字符串 ,排列组合
- 如何确定第一个字符
- 如果第一个字符是’a’,那么k必定小于或者等于 C m + n − 1 m C_{m+n-1}^{m} Cm+n−1m,n = n - 1
- 如果大于 C n − 1 m C_{n-1}^{m} Cn−1m,那么第一个字符为’z’, k = k - C m + n − 1 m C_{m+n-1}^{m} Cm+n−1m, m = m - 1
- 之后循环迭代,逐渐缩小问题规模,直至
n <= 0 || m <= 0
- 判断是否 能找到字符串,就是判断跳出循环后k是否为1,因为 后面就只剩‘aaaaaaaa’或者’zzzzzzzzzz’了
import java.util.*;
public class Main {
public static long count(long n, long m, long k)
{
long count = 1;
for (int i = 0; i < n - 1; i++) {//求组合数
count *= n - 1 + m - i;
count /= (i + 1);
if (count > k)
return count;//防止越界。count>k就可以退出计算了
}
return count;
}
public static void main(String[] args)
{
long n, m, k;
Scanner sc = new Scanner(System.in);
n = sc.nextInt();
m = sc.nextInt();
k = sc.nextInt();
String res = "";
while (m > 0 && n > 0)
{
long cnt = Main.count(n, m, k);
if (k <= cnt)
{
res += "a";
n--;
}
else
{
res += "z";
m--;
k -= cnt;
}
}
if (k != 1)
{
System.out.println(-1);
return;
}
else
{
while(n-- > 0)
res += "a";
while(m-- > 0)
res += "z";
}
System.out.println(res);
}
}