当前位置: 首页 > wzjs >正文

北京做网站好什么网站可以做简历

北京做网站好,什么网站可以做简历,深圳建站软件,两个女孩子怎么做网站记录今天的算法学习与复习。 1234. 替换子串得到平衡字符串 题目 思路 核心思路: 滑动窗口 解题过程 根据题意,一个字符串 s 被认为是平衡的,当且仅当 ‘Q’, ‘W’, ‘E’, ‘R’ 四种字符在 s 中出现的次数都相等(即 n/4)。…

记录今天的算法学习与复习。


1234. 替换子串得到平衡字符串

题目

题目截图

思路

核心思路: 滑动窗口

解题过程

根据题意,一个字符串 s 被认为是平衡的,当且仅当 ‘Q’, ‘W’, ‘E’, ‘R’ 四种字符在 s 中出现的次数都相等(即 n/4)。我们需要找到一个最短的子串,替换它之后能让整个字符串变平衡。

反向思考:如果我们要替换子串 s[l..r],那么这个子串 之外 的字符 s[0...l-1]s[r+1...n-1] 是保持不变的。为了使 整个 字符串最终平衡,这些 不变 的字符中,每种字符 (‘Q’, ‘W’, ‘E’, ‘R’) 的数量都不能超过 n/4。如果某个字符在子串外部的数量已经超过 n/4,那么无论我们如何修改子串 s[l..r],都无法使该字符的总数降到 n/4,也就无法使整个字符串平衡。

因此,我们的目标是找到一个最短的窗口 [left, right](代表要替换的子串),使得窗口 之外 的所有字符计数 (total_count[char] - window_count[char]) 均 <= n/4

我们可以使用滑动窗口来解决这个问题:

  1. 先统计整个字符串 s 中各字符的出现次数 hash[c]
  2. 如果初始状态已经是平衡的,直接返回 0。
  3. 初始化 left = 0, right = 0。扩展右边界 right,并将 s[right] 的计数从 hash 中减去(表示这个字符现在在窗口内,不属于 “窗口外” 的部分了)。
  4. 检查当前窗口是否满足条件:即窗口外的所有字符计数 (hash['Q'], hash['W'], hash['E'], hash['R']) 是否都 <= n/4
  5. 如果满足条件,说明当前窗口 [left, right] 是一个潜在的可替换子串。我们尝试缩小窗口以找到最短长度:记录当前窗口长度 right - left + 1 并更新最小值 ret;然后将 s[left] 的计数加回 hash(表示 s[left] 移出窗口,回到 “窗口外” 的部分),并将 left 右移。重复此步骤直到条件不再满足。
  6. 继续扩展右边界 right,重复步骤 3-5,直到 right 到达字符串末尾。
  7. 最终 ret 中存储的就是最短的可替换子串长度。

复杂度

  • 时间复杂度: O ( n ) O(n) O(n),其中 n 是字符串的长度。每个字符最多被 leftright 指针访问两次。
  • 空间复杂度: O ( C ) O(C) O(C) O ( 1 ) O(1) O(1),其中 C 是字符集的大小 (QWER,为常数)。我们使用了一个固定大小的哈希数组来存储字符计数。

Code

import java.util.Arrays;class Solution {public int balancedString(String ss) {char[] s = ss.toCharArray();int n = s.length;// m 是每个字符的目标数量int m = n / 4;// ret 初始化为一个不可能的最大值int ret = n;// 统计整个字符串的字符计数int[] hash = new int[128];for (char c : s) {hash[c]++;}// 检查初始字符串是否已经平衡if (hash['Q'] == m && hash['W'] == m && hash['E'] == m && hash['R'] == m) {return 0;}// 滑动窗口for (int left = 0, right = 0; right < n; right++) {// 字符 s[right] 进入窗口,将其从 "窗口外计数" 中移除hash[s[right]]--;// 检查窗口外的字符计数是否都满足 <= m// 如果满足,尝试缩小窗口while (left <= right && hash['Q'] <= m && hash['W'] <= m && hash['E'] <= m && hash['R'] <= m) {// 更新最短窗口长度ret = Math.min(ret, right - left + 1);// 字符 s[left] 离开窗口,将其加回 "窗口外计数"hash[s[left]]++;// 缩小窗口左边界left++;}}// 最终结果return ret;}
}

682. 棒球比赛

题目

题目截图

思路

核心思路: 模拟 / 栈 (可以用数组模拟)

解题过程

题目描述了一个计分系统,包含四种操作。我们可以使用一个列表或数组来模拟记录有效得分的过程,其行为类似于栈:

  1. 遍历操作数组 ops
  2. 维护一个记录有效分数的列表(或数组和指针)。
  3. 根据当前操作 ops[i] 执行相应逻辑:
    • 如果是整数 x:将其转换为数字,添加到分数列表末尾。
    • 如果是 "+":取列表末尾的两个分数,求和,并将和添加到列表末尾。
    • 如果是 "D":取列表末尾的分数,乘以 2,并将结果添加到列表末尾。
    • 如果是 "C":移除列表末尾的分数(使其无效)。
  4. 遍历结束后,计算分数列表中所有分数的总和。

在提供的代码中,使用了数组 nums 和指针 index 来模拟这个过程,index 指向下一个可以插入元素的位置,同时也表示当前有效分数的数量。

复杂度

  • 时间复杂度: O ( n ) O(n) O(n),其中 n 是操作数组 ops 的长度。需要遍历一次数组。
  • 空间复杂度: O ( n ) O(n) O(n),在最坏的情况下(例如所有操作都是数字),需要存储 n 个分数。

Code

class Solution {public int calPoints(String[] ops) {int n = ops.length;// 使用数组模拟栈来存储有效分数int[] nums = new int[n];// index 指向下一个可插入位置,也代表当前有效分数数量int index = 0;for (int i = 0; i < n; i++) {switch (ops[i]) {case "C":// 使上一个分数无效,index 后退// 注意:这里直接将值设为 0 也可以,但 index-- 更符合栈的移除操作// 后面求和时,无效位置的值不应被计算,但因为 index 减少了,循环求和时自然会跳过if (index > 0) { // 防止对空栈执行 C 操作index--;// 可选:nums[index] = 0; 清零非必需,因为求和只到 index}break;case "D":// 将上一个分数翻倍并压入if (index > 0) { // 确保有上一个分数nums[index] = nums[index - 1] * 2;index++;}break;case "+":// 将最后两个分数的和压入if (index >= 2) { // 确保有最后两个分数nums[index] = nums[index - 1] + nums[index - 2];index++;}break;default:// 是数字,直接解析并压入int val = Integer.parseInt(ops[i]);nums[index++] = val;break;}}// 计算所有有效分数的总和int sum = 0;for (int i = 0; i < index; i++) { // 只对 index 之前的有效分数求和sum += nums[i];}return sum;}
}

53. 最大子数组和(复习)

题目

题目截图

复习笔记

这次重写依然采用动态规划(或者说是在线处理)的思路。核心思想是:对于数组中的每一个元素 nums[i],以它结尾的最大子数组和要么是 nums[i] 本身(即从 nums[i] 开始一个新的子数组),要么是 nums[i] 加上以 nums[i-1] 结尾的最大子数组和(即将 nums[i] 加入到前面的子数组中)。

我们用 curSum 记录以当前元素结尾的最大子数组和。状态转移方程为:
curSum = Math.max(nums[i], curSum + nums[i])

同时,我们需要一个变量 maxSum 来记录遍历过程中遇到的所有 curSum 的最大值,这就是全局的最大子数组和。

这次复习过程中,对这个状态转移的理解和应用还算顺利,但需要确保完全内化,做到不假思索地写出。

具体解题思路回顾请看 3月23号的算法题。

复杂度

  • 时间复杂度: O ( n ) O(n) O(n),只需要一次遍历。
  • 空间复杂度: O ( 1 ) O(1) O(1),只使用了常数个额外变量。

Code

class Solution {public int maxSubArray(int[] nums) {// 初始化 curSum 和 maxSum 为第一个元素的值int curSum = nums[0];int maxSum = nums[0];// 从第二个元素开始遍历for (int i = 1; i < nums.length; i++) {// 决定是开启新子数组还是加入原子数组curSum = Math.max(nums[i], curSum + nums[i]);// 更新全局最大和maxSum = Math.max(curSum, maxSum);}return maxSum;}
}

1652. 拆炸弹(复习)

题目

题目截图

复习笔记

解题方法依然是滑动窗口。关键在于处理 k 的三种情况:

  1. k == 0: 结果数组所有元素都是 0。
  2. k > 0: 对于 code[i],需要求和 code[i+1]code[i+k](注意数组循环)。
  3. k < 0: 对于 code[i],需要求和 code[i-1]code[i+k](即 code[i-|k|]code[i-1], 注意数组循环)。

为了统一处理 k > 0k < 0 的情况,代码中使用了一个技巧:

  • k < 0 时,先将原数组 code 反转,然后令 a = |k|。这样问题就转换成了求解反转后数组的 “向后” a 个元素的和。
  • 计算完结果数组 ret 后,如果 k < 0,再将 ret 反转回来,得到最终答案。

这样,主要的计算逻辑就只需要处理 k > 0(或等价的 a > 0)的情况,即计算每个位置之后 a 个元素的和。这可以通过滑动窗口实现:

  • 先计算出 ret[0] 的值,即 code[1]code[a] 的和 (注意处理循环下标)。
  • 然后窗口向右滑动,对于 ret[i] (当 i > 0),其和可以通过 ret[i-1] 的和减去 code[i](移出窗口的元素)并加上 code[i+a](移入窗口的元素)得到 (注意处理循环下标)。

本次复习遇到的问题:

  • 忘记在处理 k < 0 之前,无论 k 正负,都应该先用 a 保存 k 的绝对值或原始值(根据后续逻辑决定)。代码中是在 a < 0 时才赋值,应在开始就处理 a = Math.abs(k) 或类似逻辑。(修正后的代码在判断 k<0 后设置 a = -k,并在反转数组后使用 a 作为正数窗口大小,是正确的处理方式)
  • 滑动窗口更新 sumret[left] 的逻辑细节:sum 的更新应该是 sum = sum - code[left] + code[right],并且 ret[left] 应该在 sum 更新 之后 赋值(或者在更新前赋值 ret[left-1] 的结果)。代码中的 sum += (code[right] - code[left])ret[left] = sum; left++; 逻辑是正确的,它计算的是下一个位置 left 的结果。

具体解法回顾请看 3月23号的算法题。

复杂度

  • 时间复杂度: O ( n ) O(n) O(n),滑动窗口遍历一次。如果 k < 0,两次数组反转也是 O ( n ) O(n) O(n)
  • 空间复杂度: O ( n ) O(n) O(n),需要一个额外的数组 ret 来存储结果。如果允许原地修改(题目通常不允许),可以做到 O ( 1 ) O(1) O(1)

Code

class Solution {public int[] decrypt(int[] code, int k) {int n = code.length;int[] ret = new int[n];// k == 0 的情况if (k == 0) {// 结果数组默认为 0,无需操作return ret;}// 为了统一处理 k > 0 和 k < 0,我们用 a 代表窗口大小 (绝对值)int a = Math.abs(k);// 如果 k < 0,先反转数组,问题变为向后求和if (k < 0) {reverse(code);}// 计算初始窗口 [1, a] 的和 (注意下标循环)int sum = 0;for (int i = 1; i <= a; i++) {// 使用模运算处理循环下标sum += code[i % n];}// 计算 ret[0]ret[0] = sum;for (int i = 1; i < n; i++) {sum = sum - code[i % n] + code[(i + a) % n];ret[i] = sum;}if (k < 0) {reverse(ret);}return ret;}// 辅助函数:反转数组private void reverse(int[] arr) {int left = 0, right = arr.length - 1;while (left < right) {int tmp = arr[left];arr[left] = arr[right];arr[right] = tmp;left++;right--;}}
}
http://www.dtcms.com/wzjs/533075.html

相关文章:

  • 网站表格怎么做的深圳市哪里最繁华
  • 和佳网站建设绵阳吉工建设
  • 西安网站seo技术厂家奢侈品网站排名
  • 一般网站的字体大小像优酷平台网站是怎么做的
  • 新手怎么用DW建设一个网站海外广告公司
  • 哈尔滨快速建站案例二级网站域名
  • 商务网站建设PDF下载wordpress一键关注
  • 做网站创业流程图重庆网上房地产官网查询
  • DW怎么做电商网站仿网链网站源代码下载
  • 北京城建建设工程有限公司网站怎么做时光网站
  • 用html5设计个人网站修改wordpress登录地址
  • 提供做网站重庆在线最新招聘信息
  • 微信小程序开发零基础入门网站关键词如何优化上首页
  • 网站做数学题wordpress二次开发难吗
  • 陕西网站建设策划内容中国早期互联网公司
  • 北京网站seo收费标准vps远程桌面服务器
  • 比较好的网站公司WordPress添加运行时间
  • 百度网站建设流程北京网站开发哪家专业
  • 北京大兴网站建设首选公司宣传片视频创意
  • 如何自己制作一个网站wordpress 归档
  • 大连设计网站的公司网站如何建设二级域名代理
  • 展示型网站建设流程wordpress建站产品导入不同目录
  • wordpress文章摘要调用长沙seo网络营销推广
  • 网站建设与规划实验报告福建省建住房建设部网站
  • 代做动画毕业设计的网站工作室建设
  • 手机微信小程序开发教程seo综合查询站长工具怎么用
  • 做政协网站的目的是什么做网站的画布是多少
  • 网站开发学校如何做拼多多商城官网站
  • 厦门市建设局查询保障摇号网站首页服务平台图片
  • 网站开发的收获体会房子做水电的时候是不是要先埋网站