【LeetCode题解】1599. 经营摩天轮的最大利润(模拟)+466. 统计重复个数+2487. 从链表中移除节点(调用栈+递归+翻转链表)+2397. 被列覆盖的最多行数

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. 统计重复个数

在这里插入图片描述

思路:
  1. ​ s1表示要重复的序列。n1表示要重复s1的次数。
    ​ s2表示要判断的子序列。n2表示子序列s2在整个序列中重复的次数。返回值表示子序列s2在重复序列s1中出现的次数。
  2. 定义一个二维数组d,其中有n行,每行只有一个元素
  3. 遍历子序列s2的每个字符
  4. 遍历重复序列s1的每个字符,统计子序列s2在重复序列s1中出现的次数
  5. 如果重复序列s1的第k个字符等于子序列s2的第j个字符
  6. j自增后等于n,说明已经遍历完子序列s2的所有字符,需要从头开始再次匹配,j清空
  7. 将统计的次数和当前j的值存入二维数组d的第i行。
  8. 循环直到s1的次数走完为止,将二维数组d中第j行的统计次数累加到ans中,更新j的值为二维数组d中第j行的下一个字符的位置
  9. 求子序列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; // 返回结果
}

点击移步博客主页,欢迎光临~

偷cyk的图

  • 16
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
给定一个整组 nums 和一个目标值 target,要求在找出两个数的和等于目标值,并返回这两个数的索引。 思路1:暴力法 最简单的思路是使用两层循环遍历组的所有组合,判断两个数的和是否等于目标值。如果等于目标值,则返回这两个数的索引。 此方法的时间复杂度为O(n^2),空间复杂度为O(1)。 思路2:哈希表 为了优化时间复杂度,可以使用哈希表来存储的元素和对应的索引。遍历组,对于每个元素nums[i],我们可以通过计算target - nums[i]的值,查找哈希表是否存在这个差值。 如果存在,则说明找到了两个数的和等于目标值,返回它们的索引。如果不存在,将当前元素nums[i]和它的索引存入哈希表。 此方法的时间复杂度为O(n),空间复杂度为O(n)。 思路3:双指针 如果组已经排序,可以使用双指针的方法来求解。假设组从小到大排序,定义左指针left指向组的第一个元素,右指针right指向组的最后一个元素。 如果当前两个指针指向的的和等于目标值,则返回它们的索引。如果和小于目标值,则将左指针右移一位,使得和增大;如果和大于目标值,则将右指针左移一位,使得和减小。 继续移动指针,直到找到两个数的和等于目标值或者左指针超过了右指针。 此方法的时间复杂度为O(nlogn),空间复杂度为O(1)。 以上三种方法都可以解决问题,选择合适的方法取决于具体的应用场景和要求。如果组规模较小并且不需要考虑额外的空间使用,则暴力法是最简单的方法。如果组较大或者需要优化时间复杂度,则哈希表或双指针方法更合适。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值