文章目录
2182. 构造限制重复的字符串
思路:
按照字符出现次数从高到低的顺序进行重复,通过维护一个指针 j
来寻找下一个非零出现次数的字母。同时,利用 StringBuilder
对象可以高效地构建字符串,避免频繁的字符串拼接操作
- 首先,创建一个长度为26的数组
cnt
,用于统计字符串s
中每个字符出现的次数。数组的下标对应字母表中的字母,通过s.charAt(i) - 'a'
可以得到字符在字母表中的位置,然后将对应位置的计数器加1。 - 创建一个
StringBuilder
对象ans
,用于构建最终结果。 - 从字母表的最后一个字母 ‘z’ 开始,依次处理每个字母。同时维护一个指针
j
,初始值为当前字母的前一个字母下标i-1
。 - 进入一个循环,直到当前字母的出现次数为0。在循环中,主要进行以下操作:
- 将当前字母重复的次数与限制次数
repeatLimit
取较小值,设为变量k
。使用for
循环遍历k
次,将当前字母添加到ans
中,并将字母的计数器减1。 - 如果当前字母的出现次数为0,则跳出内部循环。
- 在内部循环中,需要寻找下一个非零出现次数的字母,即从
j
开始向前搜索。如果找到了下一个字母(即j >= 0
并且cnt[j] != 0
),则将其添加到ans
中,并将该字母的计数器减1。 - 如果找不到下一个字母,则跳出外部循环。
- 将当前字母重复的次数与限制次数
- 最终,返回
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
思路:
- 创建一个虚拟节点
dummy
作为头节点的前置节点。 - 使用两个指针
pre
和cur
分别指向前一个非重复元素和当前节点。 - 遍历链表,当cur不为空时执行以下操作:
- 如果
cur
和cur
的下一个节点的值相等,则一直向后遍历找到下一个不相等的节点。 - 如果
pre
的下一个节点就是cur
,说明当前节点没有重复,将pre
移动到cur
的位置。 - 如果
pre
的下一个节点不是cur
,说明当前节点有重复,将pre
的next
指针指向cur
的下一个节点,实现删除操作。
- 如果
- 继续遍历下一个节点,直到遍历完整个链表。
- 返回虚拟节点的下一个节点,即为去重后的链表
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;
}