每天刷两道题——第五天

文章介绍了如何使用动态规划求解给定矩阵中非零偏移下降路径的最小数字和问题,以及如何利用哈希表(Counter)统计至少能与其他服务器通信的服务器数量。

1.1下降路径最小和

给你一个 nxnn x nnxn 整数矩阵 gridgridgrid ,请你返回非零偏移下降路径数字和的最小值。其中非零偏移下降路径定义为:从 gridgridgrid 数组中的每一行选择一个数字,且按顺序选出来的数字中,相邻数字不在原数组的同一列

输入:grid = [[1,2,3],[4,5,6],[7,8,9]]
输出:13
解释:所有非零偏移下降路径包括:
[1,5,9], [1,5,7], [1,6,7], [1,6,8],
[2,4,8], [2,4,9], [2,6,7], [2,6,8],
[3,4,8], [3,4,9], [3,5,7], [3,5,9]
下降路径中数字和最小的是 [1,5,7] ,所以答案是 13 。

代码

1.for _ in range的用法

#_可以替换成任何符合规定的字符串
a = ['a' for _ in range(5)]
#['a', 'a', 'a', 'a', 'a']
b = [['a' for _ in range(2)]for _ in range(3)]
#[['a', 'a'],['a', 'a'],['a', 'a']]

2.解题代码
动态规划:令状态f[i][j]f[i][j]f[i][j]表示从数组 gridgridgrid的前iii 行中的每一行选择一个数字,并且第iii行选择的数字为 grid[i][j]grid[i][j]grid[i][j] 时,可以得到的路径和最小值。f[i][j]f[i][j]f[i][j] 可以从第i−1i−1i1 行除了 f[i−1][j]f[i−1][j]f[i1][j] 之外的任意状态转移而来,状态转移方程:
f[i][j]={grid[0][j]if i==0min(f[i−1][k])+grid[i][j]if i /=0,j /=kf[i][j]= \begin{cases} grid[0][j] &\text{if } i==0\\ min(f[i-1][k])+grid[i][j]&\text{if } i\mathrlap{\,/}{=}0,j\mathrlap{\,/}{=}k \end{cases}f[i][j]={grid[0][j]min(f[i1][k])+grid[i][j]if i==0if i/=0,j/=k

class question1:
    def minFallingPathSum(self,grid):
        n=len(grid)  #数组的深度
        f=[[10**4 for _ in range(n)] for _ in range(n)] 
        #n*n的二维数组,假设数组的每个输入的都小于10**4=10000
        for i in range(n):
            f[0][i]=grid[0][i]
        for i in range(n):
            for j in range(n):
                for k in range(n):
                    if j!=k:
                        f[i][j]=min(f[i][j],f[i-1][k]+grid[i][j])
                        #当前的f[i][j]为上一状态到这里的路径最小和
                        #因此还需要和不同选择的f[i][j]作对比,选最小的更新
        return min(f[n-1])

q = question1()
print(q.minFallingPathSum([[1,2,3],[4,5,6],[7,8,9]]))

1.2统计参与通信的服务器

这里有一幅服务器分布图,服务器的位置标识在 m∗nm * nmn 的整数矩阵网格 gridgridgrid 中,1 表示单元格上有服务器,0 表示没有。如果两台服务器位于同一行或者同一列,我们就认为它们之间可以进行通信。请你统计并返回能够与至少一台其他服务器进行通信的服务器的数量
在这里插入图片描述

输入:grid = [[1,1,0,0],[0,0,1,0],[0,0,1,0],[0,0,0,1]]
输出:4
解释:第一行的两台服务器互相通信,第三列的两台服务器互相通信,但右下角的服务器无法与其他服务器通信

哈希表:用来实现键值对结构,将任意长度的数据映射到有限长度的域上。

代码

from collections import Counter
class question1:
 def countServers(self,grid):
        m,n=len(grid[0]),len(grid)
        rows,cols=Counter(),Counter() #哈希表,键值对
        for i in range(m): #计算每行每列有多少个服务器
            for j in range(n):
                if grid[i][j]==1:
                    rows[i]+=1  #直接添加,时间复杂度为O(1)
                    cols[j]+=1
        ans=0
        for i in range(m):
            for j in range(n):
                if grid[i][j]==1 and (rows[i]>1 or cols[j]>1):
               #如果当前有服务器并且他的行或者列上有其他的服务器就可以认为该服务器可以通信
                    ans+=1
        return ans
q = question1()
print(q.countServers([[1,1,0,0],[0,0,1,0],[0,0,1,0],[0,0,0,1]]))

Counter函数

Counter目的是用来跟踪值出现的次数。它是一个无序的容器类型,以字典的键值对形式存储,其中元素作为key,其计数作为value。计数值可以是任意的Interger(包括0和负数)。

    def testCounter(self):
        c = Counter("abcdefgab")
        c1 = Counter({'a': 4, 'b': 2})  # 从一个字典对象创建
        c2 = Counter(a=3, b=5)  # 从一组键值对创{'b': 5, 'a': 3}
        print(c["a"])  #2
        lc=list(c) # 将c中的键转为列表
        sc=set(c)  # 将c中的键转为set
        dc=dict(c) # 将c中的键转为字典
        print("lc={},sc={}.dc={},c1={},c2={},c={}".format(lc, sc, dc,c1,c2,c))
你问得非常好,这四个问非常关键: > **“我这个基础去可以吗?一天能学多少道?要不要补基础?推荐什么课?”** 我会一个一个地、**结合你的实际情况**(已经完成了四道典型目),给你最真实、最实用的建议。 --- ## ✅ 1. 我这个基础去可以吗? ### 💬 答案:✅ 可以开始了,但要“有策略地”,不是盲目! ### 🔍 分析你的现状: | 能力 | 情况 | |------|------| | 基本语法 | ✅ 会 `cin/cout`、`for` 循环、`if` 判断 | | 数组和字符串 | ✅ 会遍历、计数、处理字符 | | 面向对象 | ✅ 写过 `Point` 类,理解构造函数 | | 算法思维 | ✅ 掌握二分查找的基本思想 | | 编程工具 | ✅ 能写完整程序并提交 AC | 🎯 结论: 你已经具备了 **“入门级算法学习者”** 的能力! 你现在最需要的不是“再学一年基础”,而是: > **通过来巩固知识 + 提升信心 + 建立方法论** --- ## ✅ 2. 一天能学习多少道?怎么安排? ### 💬 答案:每天 **1~2 道** 就够了,关键是“吃透”。 不要追求“一天十道”,那是假努力。你要的是真掌握。 ### 📅 推荐每日节奏(适合学生/上班族): ```text 晚上 或 周末:60~90分钟 ├── 第1步:读 + 拆解(15分钟) │ → 看不懂就多读两遍,画图帮助理解 ├── 第2步:尝试自己写代码(30分钟) │ → 不会就看一点提示,别直接抄答案 ├── 第3步:调试 + 修改(20分钟) │ → 打印中间变量,检查哪里出错 └── 第4步:总结收获(10分钟) → 记录知识点、易错点、学到的新技巧 ``` 📌 **记住一句话:** > “一天搞懂一道,胜过一天看完十道。” --- ## ✅ 3. 要不要从基础补起? ### 💬 答案:不需要系统补课,但需要“边做边补”! 你已经有足够的基础,不需要再花几个月去听《C++ 从零到精通》这种大课。 ✅ 正确做法是: **以“为主线”,遇到不会的知识点再回头专项突破** ### 🎯 推荐“按需补基础”的方式: | 遇到的问 | 回头补什么 | |-----------|------------| | 不会用数组存数据 | 复习 `int arr[10]; for(i=0;i<n;i++) cin>>arr[i];` | | 忘了类怎么定义 | 看回你写的 `Point` 类,抄一遍 | | 不懂 `while(cin>>x)` | 学“多组输入处理”这一小节 | | 看不懂 `mid = left + (right-left)/2` | 补“二分防溢出”技巧 | 📌 这叫 **“问驱动学习法”** —— 有问才学,效率最高! --- ## ✅ 4. 推荐什么课?有没有免费资源? ### 💬 答案:不推荐长篇大论的视频课!推荐以下 **精准、高效、免费的学习资源** ### 🌐 免费优质平台推荐(中文+适合初学者) | 平台 | 推荐内容 | 特点 | |------|----------|------| | [**B站 - “黑马程序员 C++**](https://www.bilibili.com/video/BV1hB4y1T7bL)” | 前10讲:基本语法、循环、数组 | 免费、语速慢、适合零基础 | | [**菜鸟教程 - C++**](https://www.runoob.com/cplusplus/cpp-tutorial.html) | 查语法、看例子 | 在线运行代码,随时测试 | | [**洛谷 - 新手村**](https://www.luogu.com.cn/training/1) | 路线图 | 目由易到难,配套解丰富 | | [**LeetCode 力扣 - 探索卡片**](https://leetcode.cn/explore/) | “初级算法”、“二分查找”专 | 交互式学习,带测试用例 | 🎯 **重点推荐路径:** 1. B站看前5讲(变量、循环、数组) 2. 菜鸟教程查不懂的语法 3. 洛谷“新手村”实战 4. LeetCode 巩固算法 --- # 🗓️ 综合学习计划(优化版 · 适合你当前水平) | 时间 | 目标 | 具体任务 | |------|------|----------| | **第1周**<br>巩固已学 | 把四道变成“自己的模板” | 每天重写一道,直到闭眼都能写出来 | | **第2周**<br>扩展练习 | 5 道同类 | 在洛谷找“字符串处理”、“简单数学”标签的 | | **第3周**<br>专项突破 | 攻克“二分查找”和“类设计” | 每类各练2道,整理模板 | | **第4周**<br>模拟实战 | 完成一次“小型编程考试” | 限时60分钟完成3道,全部AC | 📌 每周休息1天,保持节奏不崩溃 --- ## 🧩 给你定制的“第一周每日打卡表” | 天数 | 任务 | 是否完成 ✔️ | |------|------|-------------| | Day 1 | 重新写“数字字符统计”,不看原码 | □ | | Day 2 | 重新写“Point类求最远距离” | □ | | Day 3 | 重新写“mySqrt(x)”函数 + 主函数 | □ | | Day 4 | 给每道加注释,写成“教学版本” | □ | | Day 5 | 总结四道共用的数据结构和技巧 | □ | | Day 6 | 在纸上默写任意一道的完整代码 | □ | | Day 7 | 自己出一道类似的(比如统计字母) | □ | 👉 完成后截图发给我,我可以帮你批改! --- ## 💬 最后送你三句话鼓励: 1. > “你现在的水平,已经超过了80%刚开始学编程的人。” 2. > “不要怕慢,只要不停,你就一定会跑到终点。” 3. > “每一个高手,都曾是一个连 for 循环都写不对的 beginner。” --- 如果你愿意,我现在就可以为你: - 生成一份 PDF 打卡表 - 推荐3道适合你当前水平的练习 - 提供每一的详解思路 只等你说一句:“老师,我准备好了!” 💪❤️亲爱的同学: 你这句话让我特别感动,因为你说:“我基础太差劲了”,但你还在坚持提问、努力学习。这说明你不是“差”,而是**正在变强的路上**!💪 --- ## 🌱 别担心,每个人都是从“什么都不会”开始的 你现在觉得函数和指针很难,是因为它们是编程里的“抽象概念”。就像小时候学加减法也要慢慢来一样,编程也需要时间理解和练习。 > ✅ **你不是学不会,只是还没学会。** --- # 💡 我教你一个“零基础也能懂”的方法:用生活打比方! 我们不用术语,就用你每天经历的事情来理解代码。 --- ## 🔹 一、什么是“函数”?—— 它就像“按钮” ### 生活例子:洗衣机上的按钮 - 洗衣机上有几个按钮: - “快速洗” - “强力洗” - “脱水” - 你按下“快速洗”,它就会自动完成一系列动作(进水 → 搅拌 → 排水 → 脱水) 👉 这个“快速洗”按钮,就是一个“函数”。 --- ### 编程中的函数 = 按钮 ```cpp void washQuick() { cout << "进水..." << endl; cout << "搅拌..." << endl; cout << "排水..." << endl; } ``` - `washQuick()` 就是一个函数(按钮) - 主程序中只要写 `washQuick();` —— 就像按了一下按钮 - 程序就会自动执行里面的三句话 🎯 所以记住: > **函数 = 把一堆操作打包成一个名字,以后想用就“调用这个名字”** --- ### 为什么要有函数? 想象一下: 如果你每次洗衣服都要手动输入: ``` 进水... 搅拌... 排水... ``` 写了10次洗衣程序,你就得抄10遍! 但如果有个按钮叫 `washQuick()`,你只需要写: ```cpp washQuick(); washQuick(); ``` ✅ 写两次就行!省事、不易出错、改起来也方便(只改一次函数内容) --- ### 小结:函数就是“功能按钮” | 生活 | 编程 | |------|-------| | 按“煮饭”按钮 | 调用 `cookRice()` 函数 | | 按“启动汽车” | 调用 `startCar()` 函数 | | 按“播放音乐” | 调用 `playMusic()` | 📌 口诀:**“定义一次,使用多次;改一处,全生效”** --- ## 🔹 二、什么是“指针”?—— 它就像“遥控器” ### 生活例子:电视遥控器 - 遥控器本身不是电视 - 但它能控制电视 - 你可以用遥控器打开电视、换台、调音量 👉 遥控器“指向”电视,并可以操作它。 这就是“指针”的本质! --- ### 在程序里: ```cpp Point p; // 创建一个点(真正的电视机) Point* ptr; // 定义一个指针(遥控器) ptr = &p; // 让遥控器对准这台电视(& 表示“地址”) ``` - `ptr` 是一个指针,它不存数据,只存“某个对象的位置” - `&p` 表示“p 的地址”(相当于电视机放在客厅第3排第5座) - `ptr->setXY(3,4)` 表示“通过遥控器让电视设置坐标” 📌 所以: > **指针就是一个“遥控器”,它可以远程操作内存中的对象** --- ### 动态数组为啥要用指针? 回到你的代码: ```cpp Point* points = new Point[n]; // 创建 n 个点 ``` 🔹 相当于: - 你要办一场演唱会 - 观众人数还不知道(用户输入 n) - 于是你临时租一块地,建 `n` 个座位(new) - `points` 是这个场地的“总遥控器”,可以控制每一个座位上的观众 你想访问第 i 个人?写: ```cpp points[i].setXY(x, y); ``` 或者更专业地说: ```cpp (points + i)->setXY(x, y); // 像遥控器调频道一样移动 ``` --- ### 小结:指针就是“遥控器” | 生活 | 编程 | |------|-------| | 遥控器控制电视 | 指针操作对象 | | 多个遥控器可控制同一台电视 | 多个指针可指向同一个对象 | | 遥控器丢了就无法操作电视 | 指针丢失会导致内存泄漏 | 📌 口诀:**“指针不是数据,是指向数据的路标”** --- ## 🧭 给你的学习路线图(适合零基础) ### 第一步:先别怕,每天学一点点 | 时间 | 学什么 | 怎么学 | |------|--------|--------| | 第1天 | 函数是什么 | 写3个按钮函数:sayHello(), printStars(), addTwoNumbers() | | 第2天 | 带参数的函数 | 比如 `greet("小明")` 输出“你好,小明!” | | 第3天 | 返回值 | `int add(int a, int b)` 返回两数之和 | | 第4天 | 指针入门 | 学会 `int* p; p = &x; *p = 10;` | | 第5天 | 指针+数组 | 用指针遍历数组 | | 第6天 | 类和对象 | 把“学生”、“汽车”做成类 | | 第7天 | 综合实战 | 再回头看 `Point` 这道,你会发现:我能看懂了!!! | --- ## 📚 推荐你这样练习(超简单起步) ### ✅ 练习1:写一个“打招呼”函数 ```cpp #include <iostream> using namespace std; void sayHi() { cout << "嗨!我是机器人小C" << endl; } int main() { sayHi(); // 按下按钮 sayHi(); // 再按一次 return 0; } ``` 运行结果: ``` 嗨!我是机器人小C 嗨!我是机器人小C ``` --- ### ✅ 练习2:带参数的函数 ```cpp void greet(string name) { cout << "你好呀," << name << "!" << endl; } int main() { greet("小明"); greet("小红"); return 0; } ``` 输出: ``` 你好呀,小明! 你好呀,小红! ``` --- ### ✅ 练习3:最简单的指针 ```cpp int x = 5; int* p = &x; // p 是指向 x 的指针 cout << "x = " << x << endl; // 直接看 x cout << "*p = " << *p << endl; // 通过指针看 x 的值 *p = 10; // 修改指针指向的内容 cout << "现在 x = " << x << endl; // 发现 x 变了! ``` 输出: ``` x = 5 *p = 5 现在 x = 10 ``` 💡 看到了吗?`*p = 10` 改的是 `x` 的值!这就是“遥控器改变电视内容” --- ## 🎁 最后送你一句话鼓励: > **世界上没有“天生就会编程”的人,只有“一直不肯放弃”的人。** > > 你现在走的每一步,都在把你变成未来的高手。 > > 不要和别人比,只要今天的你比昨天多懂了一点点,你就赢了! --- ## 🤝 我在这里陪你 只要你愿意学,我可以: - 从最基础开始带你一步步学 - 把复杂概念变成故事讲给你听 - 给你设计简单练习 - 看你写代码、帮你改错 你不需要聪明,只需要两个字:**坚持** --- 🌱 明天我们可以从第一个练习开始: > “写一个函数,打印自己的名字。” 你准备好了吗?回复我:“我准备好了!” 我们就开始! 你不是一个人在战斗,我在。❤️总结一下 给我做一份计划表
09-28
# 🌟 为你定制的 C++ 学习计划表(零基础 → 入门) --- ## ✅ 你的现状总结 你已掌握: - 基本输入输出:`cin`, `cout` - 循环结构:`for`, `while` - 条件判断:`if-else` - 数组与字符串处理 - 简单类定义(如 `Point` 类) - 二分查找思想 🎯 结论:**可以开始系统 + 巩固基础** --- ## 🗓️ 全阶段学习计划(4周养成编程习惯) | 时间 | 目标 | 核心任务 | |------|------|----------| | **第1周**<br>夯实基础 | 把学过的知识变成“肌肉记忆” | 每天重写一道旧,不看答案独立完成 | | **第2周**<br>专项突破 | 攻克函数、指针、动态内存 | 学会用“生活比喻法”理解抽象概念 | | **第3周**<br>分类 | 掌握常见型模板 | 字符串处理、数学问、简单模拟 | | **第4周**<br>实战提升 | 完成一次限时编程挑战 | 在60分钟内AC 3道中等难度 | 📌 每周休息1天,保持节奏不崩溃 --- ## 📆 第一周每日打卡计划(巩固已有成果) | 天数 | 今日任务 | 是否完成 ✔️ | |------|----------|-------------| | Day 1 | 重写“数字字符统计”程序,不看原码 | □ | | Day 2 | 重写“Point类求最远距离”,写出完整类定义 | □ | | Day 3 | 重写 `mySqrt(x)` 函数 + 主函数调用 | □ | | Day 4 | 给每道添加详细注释,写成“教学版代码” | □ | | Day 5 | 总结四道共用的数据结构和技巧(如循环遍历) | □ | | Day 6 | 在纸上默写任意一道的完整代码 | □ | | Day 7 | 自己出一道新(例如:统计大写字母个数)并解答 | □ | --- ## 📚 推荐免费学习资源(精准高效,拒绝无效视频) | 平台 | 推荐内容 | 使用方式 | |------|----------|-----------| | [B站 - 黑马程序员 C++](https://www.bilibili.com/video/BV1hB4y1T7bL) | 前5讲:变量、循环、数组 | 每天看1讲,边看边敲代码 | | [菜鸟教程 - C++](https://www.runoob.com/cplusplus/cpp-tutorial.html) | 查语法、看示例 | 遇到不会的立刻搜索 | | [洛谷 - 新手村](https://www.luogu.com.cn/training/1) | 由易到难的路线 | 每周2~3道新 | | [LeetCode 探索卡片](https://leetcode.cn/explore/) | “初级算法”专 | 巩固逻辑思维 | --- ## 🔧 第二周重点突破:函数 & 指针(用生活打比方) ### 🎯 函数 = 功能按钮 ```cpp void sayHello() { cout << "你好呀!" << endl; } // 调用:sayHello(); → 就像按下洗衣机上的“快洗”按钮 ``` ### 🎯 指针 = 遥控器 ```cpp int x = 5; int* p = &x; // p 是遥控器,指向 x *p = 10; // 通过遥控器修改电视内容 → x 变成 10 ``` ### ✅ 每日小练习(从简单开始建立信心) #### Day 8:写一个打招呼函数 ```cpp #include <iostream> using namespace std; void greet(string name) { cout << "你好," << name << "!欢迎来学编程!" << endl; } int main() { greet("小明"); greet("老师"); return 0; } ``` #### Day 9:最简单的指针实验 ```cpp int a = 7; int* ptr = &a; cout << "a = " << a << endl; cout << "*ptr = " << *ptr << endl; *ptr = 99; cout << "现在 a = " << a << endl; // 输出 99! ``` --- ## 🧩 第三周目标:分类(建立解模板) | 型 | 推荐目(洛谷 or LeetCode) | 解模板关键词 | |------|-------------------------------|----------------| | 字符串统计 | 统计字母、数字、空格个数 | 遍历 + `isalpha()` / `isdigit()` | | 数学问 | 判断素数、回文数 | 循环检查条件 | | 简单模拟 | 成绩评级、日期推算 | `if-else` 分支控制 | | 数组操作 | 查找最大值、去重 | `for` 循环 + 标记变量 | 📌 每做一,记录: 1. 目类型 2. 关键代码段 3. 易错点(如边界条件) --- ## 🏁 第四周实战:模拟考试(检验学习成果) ✅ 考试规则: - 时间:60分钟 - 任务:完成以下3并全部 AC - 平台:洛谷 或 LeetCode ### 📝 模拟试清单: 1. **字符串:** 统计一句话中元音字母个数 2. **数学:** 写一个函数判断是否为回文数 3. **类设计:** 定义一个 `Student` 类,包含姓名和成绩,输出最高分学生信息 👉 完成后截图发给我,我来帮你批改! --- ## 💬 最后送你三句话,陪你走完这段路: 1. > “你现在不是‘差’,你是正在变强的路上。” 2. > “不要怕慢,只要不停,你就一定会跑到终点。” 3. > “每一个高手,都曾是一个连 for 循环都写不对的 beginner。” --- ## 🤝 我在这里等你行动 只要你回复一句:“**我准备好了!**” 我就立刻为你: - 生成一份 PDF 打卡表(可打印) - 发送第一周练习的参考代码 - 提供每日作业批改服务 你不需要聪明,只需要两个字:**坚持** 🌱 我们明天就从第一个练习开始: > “写一个函数,打印自己的名字。” 准备好了吗?告诉我:“老师,我准备好了!” 💪❤️
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值