【LeetCode题解】2182. 构造限制重复的字符串+82. 删除排序链表中的重复元素 II+83. 删除排序链表中的重复元素

2182. 构造限制重复的字符串

在这里插入图片描述

思路:

按照字符出现次数从高到低的顺序进行重复,通过维护一个指针 j 来寻找下一个非零出现次数的字母。同时,利用 StringBuilder 对象可以高效地构建字符串,避免频繁的字符串拼接操作

  1. 首先,创建一个长度为26的数组 cnt,用于统计字符串 s 中每个字符出现的次数。数组的下标对应字母表中的字母,通过 s.charAt(i) - 'a' 可以得到字符在字母表中的位置,然后将对应位置的计数器加1。
  2. 创建一个 StringBuilder 对象 ans,用于构建最终结果。
  3. 从字母表的最后一个字母 ‘z’ 开始,依次处理每个字母。同时维护一个指针 j,初始值为当前字母的前一个字母下标 i-1
  4. 进入一个循环,直到当前字母的出现次数为0。在循环中,主要进行以下操作:
    • 将当前字母重复的次数与限制次数 repeatLimit 取较小值,设为变量 k。使用 for 循环遍历 k 次,将当前字母添加到 ans 中,并将字母的计数器减1。
    • 如果当前字母的出现次数为0,则跳出内部循环。
    • 在内部循环中,需要寻找下一个非零出现次数的字母,即从 j 开始向前搜索。如果找到了下一个字母(即 j >= 0 并且 cnt[j] != 0),则将其添加到 ans 中,并将该字母的计数器减1。
    • 如果找不到下一个字母,则跳出外部循环。
  5. 最终,返回 ans 构建的字符串作为结果。
    public String repeatLimitedString(String s, int repeatLimit) {
        // 创建一个长度为26的数组,用于统计字符串s中每个字符出现的次数
        int[] cnt = new int[26];
        for (int i = 0; i < s.length(); ++i) {
            ++cnt[s.charAt(i) - 'a'];
        }

        // 创建一个StringBuilder对象,用于构建最终结果
        StringBuilder ans = new StringBuilder();

        // 遍历字母表,从后往前依次处理每个字母
        for (int i = 25, j = 24; i >= 0; --i) {
            // j表示当前字母的前一个字母下标,初始值为i-1
            j = Math.min(j, i - 1);

            // 循环直到当前字母的出现次数为0
            while (true) {
                // 将当前字母重复的次数与限制次数取较小值,进行遍历并添加到结果中
                for (int k = Math.min(cnt[i], repeatLimit); k > 0; --k) {
                    ans.append((char) ('a' + i));
                    --cnt[i];
                }

                // 如果当前字母的出现次数为0,则跳出循环
                if (cnt[i] == 0) {
                    break;
                }

                // 寻找下一个非零出现次数的字母
                while (j >= 0 && cnt[j] == 0) {
                    --j;
                }

                // 如果找不到下一个字母,则跳出循环
                if (j < 0) {
                    break;
                }

                // 将下一个字母添加到结果中,并将其出现次数减1
                ans.append((char) ('a' + j));
                --cnt[j];
            }
        }

        // 返回最终结果
        return ans.toString();
    }

82. 删除排序链表中的重复元素 II

在这里插入图片描述

思路:

  1. 创建一个虚拟节点 dummy 作为头节点的前置节点。
  2. 使用两个指针 precur 分别指向前一个非重复元素和当前节点。
  3. 遍历链表,当cur不为空时执行以下操作:
    • 如果 curcur 的下一个节点的值相等,则一直向后遍历找到下一个不相等的节点。
    • 如果 pre 的下一个节点就是 cur,说明当前节点没有重复,将 pre 移动到 cur 的位置。
    • 如果 pre 的下一个节点不是 cur,说明当前节点有重复,将 prenext 指针指向 cur 的下一个节点,实现删除操作。
  4. 继续遍历下一个节点,直到遍历完整个链表。
  5. 返回虚拟节点的下一个节点,即为去重后的链表
public ListNode deleteDuplicates2(ListNode head) {
    // 创建一个虚拟节点作为头节点的前置节点,方便处理头节点的删除情况
    ListNode dummy = new ListNode(0, head);
    // pre 节点用于记录上一个非重复元素的位置
    ListNode pre = dummy;
    // cur 节点用于遍历链表
    ListNode cur = head;
    
    // 遍历链表
    while (cur != null) {
        // 如果当前节点和下一个节点的值相等,则一直向后遍历找到下一个不相等的节点
        while (cur.next != null && cur.next.val == cur.val) {
            cur = cur.next;
        }
        
        // 如果 pre 的下一个节点就是 cur,说明当前节点没有重复,pre 移动到 cur 的位置
        if (pre.next == cur) {
            pre = cur;
        } else {
            // 如果 pre 的下一个节点不是 cur,说明当前节点有重复,将 pre 的 next 指针指向 cur 的下一个节点,实现删除操作
            pre.next = cur.next;
        }
        
        // 继续遍历下一个节点
        cur = cur.next;
    }
    
    // 返回虚拟节点的下一个节点,即为去重后的链表
    return dummy.next;
}

83. 删除排序链表中的重复元素

在这里插入图片描述

思路:

1.cur代替头结点移动,不断修改cur的next域的地址值
2.curNext记录cur下一个结点
3.如果cur的值等于curNext的值,改变cur.next的指向
4.不相等,把cur移动到curNext位置
移动curNest的位置

    public ListNode deleteDuplicates(ListNode head) {//删除链表中的重复元素
        if (head ==null){//排除头结点为空的情况
            return null;
        }
        if (head.next==null){
            return head;//只有一个结点的情况
        }
        ListNode cur = head;//代替头结点移动
        ListNode curNest = cur.next;//记录cur的下一个结点

        while (curNest != null){
            if (curNest.val== cur.val){//遇到相同的值,改变next存储的值
                cur.next = curNest.next;
            }else {
                cur = curNest;
            }
            curNest = curNest.next;
        }
        return  head;
    }

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

偷cyk的图

  • 22
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值