文章目录
- [1599. 经营摩天轮的最大利润](https://leetcode.cn/problems/maximum-profit-of-operating-a-centennial-wheel/)
- [466. 统计重复个数](https://leetcode.cn/problems/count-the-repetitions/)
- [2487. 从链表中移除节点](https://leetcode.cn/problems/remove-nodes-from-linked-list/)
- [2397. 被列覆盖的最多行数](https://leetcode.cn/problems/maximum-rows-covered-by-columns/)
1599. 经营摩天轮的最大利润
思路:
1.对摩天轮的运转情况进行模拟,
2.遍历数组,分别计算每次的当前利润、最大利润、上一轮遗留的人数
3.循环的条件为:数组没走完 、数组走完了,还剩等待的游客两种情况都进入循环
4.计算当前轮次的人 :
-
情况一(数组没走完): 第i轮之前到达地游客数量customers[i] + 上一轮留下的人lostCustomers
-
情况二(数组走完了,还剩等待的游客):当前轮次的人== 留下的人
5.如果当前轮次人数大于4,遗留的人数为= 当前轮次人数减4
- 当前的利润为每轮四个人的票钱 - 一次运行成本,利润累加
6.如果当前轮次人数小于4,剩下的人都乘坐,当前利润为这批不满4人乘客的票钱 - 一次运行成本
7.利润比较,如果当前轮利润更大,轮次加一
public int minOperationsMaxProfit(int[] customers, int boardingCost, int runningCost) {
// 最小运行次数,即答案
int minTimes = -1;
// 最大利润
int maxMoney = 0;
// 当前利润
int curMoney = 0;
// 上一轮遗留下来的人
int lostCustomers = 0;
// 当还有剩下人,或者i没遍历完,开始遍历
for (int i = 0; i < customers.length || lostCustomers > 0; i++) {
// 计算当前轮次的人
int curCustomers;
if (i < customers.length){
curCustomers = lostCustomers + customers[i];
}else {
curCustomers = lostCustomers;
}
// 大于4,则最多上车四个;否则则有几个上车几个
if ( curCustomers > 4){
lostCustomers = curCustomers - 4;
curMoney += 4 * boardingCost - runningCost;
}else {
lostCustomers = 0;
curMoney += curCustomers * boardingCost - runningCost;
}
// 如果当前轮次的利润大于备案的最大利润,则更新轮次和最大利润
if (curMoney > maxMoney){
minTimes = i + 1;
maxMoney = curMoney;
}
}
return minTimes;
}
466. 统计重复个数
思路:
- s1表示要重复的序列。n1表示要重复s1的次数。
s2表示要判断的子序列。n2表示子序列s2在整个序列中重复的次数。返回值表示子序列s2在重复序列s1中出现的次数。 - 定义一个二维数组d,其中有n行,每行只有一个元素
- 遍历子序列s2的每个字符
- 遍历重复序列s1的每个字符,统计子序列s2在重复序列s1中出现的次数
- 如果重复序列s1的第k个字符等于子序列s2的第j个字符
- j自增后等于n,说明已经遍历完子序列s2的所有字符,需要从头开始再次匹配,j清空
- 将统计的次数和当前j的值存入二维数组d的第i行。
- 循环直到s1的次数走完为止,将二维数组d中第j行的统计次数累加到ans中,更新j的值为二维数组d中第j行的下一个字符的位置
- 求子序列s2在重复序列s1中出现的平均次数
public int getMaxRepetitions(String s1, int n1, String s2, int n2) {
//s1表示要重复的序列。n1表示要重复s1的次数。
//s2表示要判断的子序列。n2表示子序列s2在整个序列中重复的次数。
// 返回值表示子序列s2在重复序列s1中出现的次数。
int m = s1.length(), n = s2.length();
//m和n,分别表示序列s1和s2的长度。
int[][] d = new int[n][0];
// 定义一个二维数组d,其中有n行,每行只有一个元素
for (int i = 0; i < n; ++i) {
//遍历子序列s2的每个字符
int j = i;//j 表示在字符串s2中出现的位置
int cnt = 0;
// 统计子序列s2在重复序列s1中出现的次数
for (int k = 0; k < m; ++k) {
//遍历重复序列s1的每个字符
if (s1.charAt(k) == s2.charAt(j)) {
//如果重复序列s1的第k个字符等于子序列s2的第j个字符
if (++j == n) {
//如果j自增后等于n,说明已经遍历完子序列s2的所有字符,需要从头开始再次匹配
j = 0;
//将j重置为0,重新从子序列s2的开头开始匹配
++cnt;
//子序列s2在重复序列s1中出现的次数加1
}
}
}
d[i] = new int[] {cnt, j};
//将统计的次数和当前j的值存入二维数组d的第i行。
}
int ans = 0;
//用于保存子序列s2在重复序列s1中出现的总次数
for (int j = 0; n1 > 0; --n1) {
///每次循环将n1减1,直到n1为0,s1的次数走完为止
ans += d[j][0];
//将二维数组d中第j行的统计次数累加到ans中。
j = d[j][1];
//更新j的值为二维数组d中第j行的下一个字符的位置
}
return ans / n2;
//子序列s2在重复序列s1中出现的平均次数
}
2487. 从链表中移除节点
方法一:调用栈
1.将所有节点按顺序压入栈中
2.从栈顶依次查看元素
3.当栈顶节点的值大于新链表表头的值,将该节点插入新链表的表头
4.否则移除该节点
public ListNode removeNodes(ListNode head) {
Deque<ListNode> stack = new ArrayDeque<>();
while (head!=null){
stack.push(head);
head = head.next;
}
while (!stack.isEmpty()){
if (head==null||stack.peek().val>=head.val){
stack.peek().next = head;
将该节点插入新链表的表头
head = stack.peek();
//表头前移
}
stack.pop();
}
return head;
}
方法二:递归
1.节点为空返回
2.不为空,对右侧节点进行判断
3.比右侧节点小,移除当前结点,返回下一个结点
4.比右侧节点大,返回当前结点
public ListNode removeNodes(ListNode head) {
if (head == null){
return null;
}
head.next = removeNodes(head.next);
if (head.next!=null && head.val < head.next.val){
return head.next;
}else {
return head;
}
}
方法三:翻转链表
1.翻转链表、要求改为:移除每一个左侧有一个更大数值的节点。
2.不断移除右结点,除非右结点的值大于等于当前结点
3.再翻转回来
public ListNode removeNodes3(ListNode head) {
head = reverse(head);
ListNode cur = head;
while (cur.next!=null){
if (cur.val>cur.next.val){
//当前值比右边值大,删除右边结点
cur.next = cur.next.next;
}else {
cur = cur.next;
}
}
return reverse(head);
//翻转回来
}
public ListNode reverse (ListNode head){
//翻转链表
ListNode dummy = new ListNode();
while (head!=null){
ListNode cur = head;
head = head.next;
cur.next = dummy.next;
dummy.next = cur;
}
return dummy.next;
}
2397. 被列覆盖的最多行数
方法:二进制枚举
1.获取矩阵的行数和列数,并创建一个大小为m
的一维数组rows
来保存每行的状态
2.通过遍历矩阵的每个元素,将每行的状态用位运算保存到rows
数组中。
3.通过使用位掩码mask
来遍历所有可能的行选择情况
4.如果mask二进制表示中1的个数不等于numSelect
,则跳过当前循环。
5.计算在当前行选择情况下,有多少行满足被选择行的状态,即与mask
进行位与运算后等于自身的行数
6.代码更新保存结果的变量ans
,取当前结果与新计算的行数满足条件的行数之间的较大值。
public int maximumRows(int[][] matrix, int numSelect) {
int m = matrix.length; // 获取矩阵的行数
int n = matrix[0].length; // 获取矩阵的列数
int[] rows = new int[m]; // 创建一个长度为m的一维数组来保存每行的状态
for (int i = 0; i < m; ++i) { // 遍历矩阵的行
for (int j = 0; j < n; ++j) { // 遍历矩阵的列
if (matrix[i][j] == 1) { // 如果当前元素为1
rows[i] |= 1 << j; // 利用位运算将当前行的状态保存到rows数组中
}
}
}
int ans = 0; // 初始化结果变量为0
for (int mask = 1; mask < 1 << n; ++mask) { // 通过位掩码mask遍历所有可能的行选择情况
if (Integer.bitCount(mask) != numSelect) { // 如果mask的二进制表示中1的个数不等于numSelect
continue; // 跳过当前循环,继续下一次循环
}
int t = 0; // 用于计数满足条件的行数
for (int x : rows) { // 遍历rows数组中的每个元素
if ((x & mask) == x) { // 如果当前行的状态与mask进行位与运算后等于自身
++t; // 将计数器t加1
}
}
ans = Math.max(ans, t); // 更新保存结果的变量ans,取当前结果与新计算的行数满足条件的行数之间的较大值
}
return ans; // 返回结果
}