Large Model-learning(2)

Day 2-Linux复习日

今天主要是速通一下linux,顺便继续看+做算法题。

今天看到别人推荐的这个书不错:Hello-Agents

1.hot100-进度8/100

复习一下前几道题,还是照常看几集灵神的课,然后做题,我是优先做简单和中等难度的,困难的放到最后。

15. 三数之和

这道题之前明明有看过,但还是忘记做法了,我下意识使用的方案2,简直做的一塌糊涂,思路也完全错了。

  1. 三个数相加等于0,等同于两个数相加的和等于负的第三个数
  2. 有两种方案可供选择:
    1. 先定下一个数,然后查找另外两个数。
    2. 先定下两个数,然后查找第三个数。
  3. 如果选择方案2,需要用到Map。因为需要对nums去重复;在Map中查找第三个数时,还需要避开已经定下的两个数,实现起来会比较麻烦。
  4. 如果选择方案1,查找另外两个数时,需要用到双指针算法。

第一种解法:双指针

排序 + 双指针 + 集合自动去重 的三数之和解法。

  • list:有序、可重复
  • set:无序、自动去重
  • 取每一个数字作为三元组的第一个数
  • nums[:len(nums)-2] 保证后面至少还有 2 个数字,才能构成三元组

还有一个知识点我搞混了:

  • add 是 **set 的方法:**不管 x 重不重复,直接往后面加
  • append 是 **list 的方法:**如果 x 已经存在,什么都不做 ;如果不存在,才加进去

时间复杂度:O(N * N)

空间复杂度:O(N)

cs 复制代码
class Solution:
    def threeSum(self, nums: list[int]) -> list[list[int]]:
        nums.sort()
        results = set()
        
        for i,num in enumerate(nums[:len(nums) - 2]):
            left = i + 1
            right = len(nums) - 1
            while left < right:
                sum_ = nums[left] + nums[right]
                if sum_ == -num:
                    results.add((num,nums[left],nums[right]))
                    left += 1
                elif sum_ > -num:
                    right -= 1
                else:
                    left += 1
        return list(results)

第二种解法:使用 Map(慢而复杂)

这个解法速度太慢,主要是了解一下思路就好。

将这道题拆分为:两数之和 + 哈希表 = 三数之和

时间复杂度:O(N * N)

空间复杂度:O(N)

cs 复制代码
# from collections import defaultdict

class Solution:
    def threeSum(self, nums: List[int]) -> List[List[int]]:
        nums = duplicate_removed_nums(nums)

        results = set()
        num_to_indices = defaultdict(list)

        for i, num in enumerate(nums):
            num_to_indices[num].append(i)

        for i in range(len(nums) - 1):
            for j in range(i + 1, len(nums)):
                if -(nums[i] + nums[j]) in num_to_indices:
                    for index in num_to_indices[-(nums[i] + nums[j])]:
                        if index not in (i, j):
                            result = [nums[i], nums[j], nums[index]]
                            result.sort()
                            results.add(tuple(result))

        return list(results)


def duplicate_removed_nums(nums):
    num_to_count = defaultdict(int)

    for i, num in enumerate(nums):
        if num_to_count[num] <= 2 or (num_to_count[num] <= 3 and num == 0):
            num_to_count[num] += 1

    new_nums = []

    for num in num_to_count:
        new_nums.extend([num] * num_to_count[num])

    return new_nums

知识点:

  • defaultdict(int):Python 专门用来计数的神器字典,用来记录每个数字出现了几次。
  • extend:把里面元素拆开放入
  • defaultdict(list):这是一个字典key:数字value:这个数字出现的所有下标(位置)列表

42. 接雨水

这道题属于困难级别,但是看过灵神的课,感觉还是有些思路,遂挑战之。

挑战失败,虽然思路对了但是一直没法实现,还是再练练吧。

我自己写的错误代码:

cs 复制代码
class Solution:
    def trap(self, height: List[int]) -> int:
        water = 0
        left = 1
        right = len(height) - 2 #10
        l_height = height
        r_height = height
        for i in height[1:len(height) - 1]:
            l_height[left] = max(l_height[left],height[left - 1])
            left += 1
            r_height[right] = max(r_height[right],height[right - 1])
            right -= 1
        for j in l_height:
            water += min(l_height[j],r_height[j]) - height[j]

        return water

最致命错误:l_height = height 是浅拷贝,不是新数组。在 Python 中,=引用赋值l_heightheight 指向同一个列表。

第一种解法:前后缀最大值

这个版本是最正确的写法。。。:

时间复杂度:O(n)

空间复杂度:O(n)

cs 复制代码
class Solution:
    def trap(self, height: List[int]) -> int:
        n = len(height)
        if n <= 2:
            return 0

        # 错误1修复:创建新数组,不是别名
        l_height = [0] * n
        r_height = [0] * n

        # 左最大值(正确写法)
        l_height[0] = height[0]
        for i in range(1, n):
            l_height[i] = max(l_height[i-1], height[i])

        # 右最大值(正确写法)
        r_height[-1] = height[-1]
        for i in range(n-2, -1, -1):
            r_height[i] = max(r_height[i+1], height[i])

        # 计算雨水(错误4修复:遍历下标)
        water = 0
        for i in range(n):
            water += min(l_height[i], r_height[i]) - height[i]

        return water

第二种解法:双指针写法(最快、最省空间)

左右两边同时往中间走,哪边柱子矮就从哪边算雨水,用两个变量记录左右最高,不用额外数组,一遍遍历就算完。

  • 时间复杂度:O(n)(只跑一遍)
  • 空间复杂度:O(1)(不用数组,只用 4 个变量)
cs 复制代码
class Solution:
    def trap(self, height: list[int]) -> int:
        left = 0
        right = len(height) - 1
        left_max = right_max = 0
        water = 0

        while left < right:
            if height[left] < height[right]:
                if height[left] >= left_max:
                    left_max = height[left]
                else:
                    water += left_max - height[left]
                left += 1
            else:
                if height[right] >= right_max:
                    right_max = height[right]
                else:
                    water += right_max - height[right]
                right -= 1
        return water

3. 无重复字符的最长子串

第一种解法:暴力(慢且不高效)

这道题我自己的解法如下:暴力枚举所有起点,往后找不重复的子串,记录最长长度

cs 复制代码
class Solution:
    def lengthOfLongestSubstring(self, s: str) -> int:
        result = 0
        for c in s:
            max_str = 0
            num_to_count = defaultdict(int)
            for i,c in enumerate(s):
                if num_to_count[c] == 0:
                    num_to_count[c] += 1
                    max_str += 1
                result = max(result,max_str)

        return result

结果通过了两个案例,最后一个没通过。

**问题:**外层多了一层完全多余的循环,导致每次还没计算完就重置当前长度和计数器;内层循环没有处理字符重复的情况,遇到重复时不会停止,逻辑不符合题目要求;同时 result 的更新位置也不对,整体结构混乱,无法正确算出最长无重复子串的长度。

更正后的正确解法:

cs 复制代码
class Solution:
    def lengthOfLongestSubstring(self, s: str) -> int:
        result = 0
        n = len(s)

        # 从每个位置 i 开始,往后找无重复子串
        for i in range(n):
            seen = set()
            current_length = 0

            for j in range(i, n):
                if s[j] in seen:
                    break  # 重复就停止

                seen.add(s[j])
                current_length += 1
                result = max(result, current_length)

        return result

时间复杂度:O (n²)

空间复杂度:O (n)

第二种解法:滑动窗口(Sliding Window) 最优解法

思路:用左右指针形成一个窗口 ,右边一直往右走,遇到重复就把左边直接跳到合法位置,全程只遍历一次字符串,最快

  • 时间复杂度:O (n)
  • 空间复杂度:O (n)
cs 复制代码
class Solution:
    def lengthOfLongestSubstring(self, s: str) -> int:
        char_index = {}  # 记录字符最后出现的位置
        left = 0         # 窗口左边界
        max_len = 0      # 最长长度

        for right, c in enumerate(s):
            # 如果字符重复,且在窗口内,左边界直接跳到重复位置+1
            if c in char_index and char_index[c] >= left:
                left = char_index[c] + 1

            char_index[c] = right
            max_len = max(max_len, right - left + 1)

        return max_len

感觉滑动窗口的题还是没有特别理解,今天先到这里,再去看几个视频缓一下。

2.Linux学习

感觉linux没有特别合适的课,直接看官方文档比较快:https://www.gnu.org/software/coreutils/manual/coreutils.html?utm_source=chatgpt.com

有基础的准备速成的可以选择性的过一遍这个up主的视频,我觉得精简但是有干货:【GeekHour】30分钟Linux入门教程 - 哔哩哔哩

2.1准备测试文件并检查

2.2基础文件和目录操作

2.3 grep 和 find

练习 1:grep 基础搜索

查找 error:

显示行号:

忽略大小写:

再练几个:

练习 2:find 查找文件

查找所有 txt 文件:

查找所有普通文件:

查找所有 log 文件:

再练几个:

练习 3:find + xargs 组合

  • find 负责找文件
  • xargs 负责把这些文件批量交给下一个命令处理

这就是 Linux 里非常常见的批量处理套路。

在所有 .txt 文件中搜索 linux

把所有普通文件用 ls -l 展示详情:

再练两个:

2.4 重定向和管道

练习 1:覆盖重定向 >

把目录列表写入文件:

再覆盖一次:(前一次内容被覆盖了)

练习 2:追加重定向 >>

>> 是在原文件后面追加

练习 3:管道 |

从日志里筛选 error:

统计日志总行数:

统计当前目录所有普通文件数量:(wc -l:统计列表的行数 = 统计文件的总数量

再练几个:

练习 4:把搜索结果输出到文件

2.5 权限、进程、端口、日志跟踪

练习 1:写一个最小 shell 脚本

创建脚本:

先直接执行,通常会报权限问题:

加执行权限:

再执行:

练习 2:查看进程

命令本身:ps

  • 全称:Process Status(进程状态)
  • 作用:列出当前系统中正在运行的进程
  • 你输入的是无参数的 ps ,只会显示当前终端(pts/4)下的进程,不会显示系统后台进程。
列名 全称 含义
PID Process ID 进程 ID(系统给每个进程分配的唯一编号,用来管理进程)
TTY Teletypewriter 终端设备(进程运行在哪个终端窗口)
TIME CPU Time 进程占用 CPU 的总时间(格式 时:分:秒
CMD Command 启动这个进程的命令 / 程序名

补充:常用 ps 拓展命令(工作中必用)

命令 作用
ps aux 查看系统所有进程的详细信息(最常用)
ps -ef 另一种格式查看所有进程
`ps -ef grep bash` 筛选出所有 bash 进程
kill 9627 强制关闭 PID 为 9627 的 bash 进程(会关闭当前终端)

看更完整的信息:

过滤 bash 相关进程:

练习 3:查看监听端口

ss -ltn = 只查看本机正在监听的 TCP 端口,并用数字形式显示

ss( Socket Statistics)

  • 作用:查看系统网络连接、端口状态
  • netstat 更快、更现代

-l → Listen(监听)

  • 只显示正在监听、等待连接的端口
  • 不显示已经连上的连接

-t → TCP

  • 只看 TCP 协议 的端口
  • 不看 UDP

-n → Numeric(数字)

  • 不把端口号翻译成名字(比如 80 不翻译成 http)
  • 直接显示数字 IP、数字端口,看得更清楚

练习 4:跟踪日志变化

打开一个终端执行:

然后再开另一个终端,往日志追加内容:

会看到 tail -f 那边实时刷新:

按Ctrl + C结束。

2.6 综合练习

任务 1:统计所有 .txt 文件行数,并写入 summary.txt

第一行是我自己想的错误答案。

区别在于:xargs 会把管道传来的多行文件路径 ,转换成 wc -l 命令的命令行参数

写法 统计对象 输出结果 是否符合需求
`find . -name "*.txt" wc -l` .txt 文件的个数(路径行数) 单个数字(文件数量) ❌ 错误
`find . -name "*.txt" xargs wc -l` 每个 .txt 文件的内容行数 分文件行数 + 总行数 ✅ 正确

任务 2:统计所有日志里包含 error 的行

是我想复杂了,以为logs文件夹下面有很多个日志文件,所以有些混乱。

任务 3:列出当前目录所有文件详情,并保存

命令 范围 显示内容 是否递归
ls -la 当前目录 文件 + 文件夹 ❌ 不递归
find ... ls -l 全部目录 只显示文件 ✅ 递归

这是两种结果的区别,还是得认真审题啊。

今日份linux学完,推送至github即可。

3.补充git知识

感觉git命令还是得练一下,还是强推这个up主的课程:【GeekHour】一小时Git教程_哔哩哔哩_bilibili

笔记的话这个链接里面up主也整理好了,我就不做笔记,大概过一遍得了。

4.Docker入门

Docker看的还是这位up主的,很适合速成/有一点基础的:【GeekHour】30分钟Docker入门教程_哔哩哔哩_bilibili

上面的视频感觉确实有点太短了,有些不知所云,所以我又自己找了点小题目实操一下。

简单的练习一下 Docker 中的命令。我是windows环境,首先在本地终端激活WSL,再在VS Code 打开就可以了,方便很多。

4.1 确认 Docker 和 WSL 打通

分别用来看:正在运行的容器、所有容器、已有镜像

**docker version:**查看 Docker 客户端和服务端版本。如果这个命令能正常输出,说明 Docker CLI 和 Docker Engine 已经联通。

**docker ps:**查看当前正在运行的容器。

**docker images:**查看本机已有的镜像。

4.2 重要概念

4.2.1镜像

镜像就是一个可重复复制的程序运行模板。

里面已经准备好了某个程序运行所需的环境、文件和依赖。

比如:

  • nginx 镜像:里面已经装好了 nginx
  • python 镜像:里面已经装好了 Python
  • pytorch/pytorch 镜像:里面已经装好了 PyTorch

4.2.2 容器

容器就是"镜像运行起来后的实例"。

  • 镜像是模板
  • 容器是模板跑起来之后的实际运行对象

在 Docker 里:nginx 是镜像

4.2.3 端口映射

容器内部有自己的网络环境。

比如 nginx 默认监听容器内部的 80 端口,但电脑浏览器访问不到容器内部的 80,除非把它映射出来。例如:

-p 8080:80

  • 本机访问 8080
  • 转发到容器内部的 80

也就是:宿主机端口 : 容器端口

4.3 运行第一个真正有用的容器

启动一个 nginx 容器,并通过浏览器访问它。

**docker run:**创建并启动一个容器。这是 Docker 最核心的命令之一。

**--name day2-nginx:**给这个容器起名字,叫 day2-nginx

-d 表示后台运行(detached mode)。如果不加 -d,容器会占着当前终端。

**-p 8080:80:**端口映射。意思是:电脑访问 8080,实际转发到容器里的 80

nginx 表示使用 nginx 这个镜像启动容器。

如果本地没有这个镜像,Docker 会自动下载。

Docker Desktop 页面也可以同步看到这个容器的情况。

此时访问 http://localhost:8080 可以看到这个页面,说明容器已经顺利运行啦。

至此,已经第一次真正完成了:

  • 使用镜像
  • 创建容器
  • 启动服务
  • 从宿主机访问容器里的服务

这就是 Docker 最核心的入门闭环。

4.4 查看容器日志

查看容器输出日志。

感觉 docker 的很多命令都和 git 有相似之处,下面这个是查看容器日志的命令。

bash 复制代码
docker logs day02-nginx

**docker logs:**查看某个容器的日志输出。

**day2-nginx:**指定你要查看日志的容器名字。

4.5 进入容器内部

进入运行中的容器,在里面查看文件和目录。

这里终端输出有点多,我直接将命令打在这里。执行:

bash 复制代码
docker exec -it day2-nginx /bin/sh

进入后其实就是进入了 linux 环境,再执行:

bash 复制代码
pwd
ls -la
ls -la /usr/share/nginx/html
cat /usr/share/nginx/html/index.html

退出:

bash 复制代码
exit

docker exec在一个已经运行中的容器里执行命令。

**-it:**以交互方式进入容器终端。

  • -i:保持输入流

  • -t:一个终端界面

**day22-nginx:**要进入的容器名字。

**/bin/sh:**在容器里启动一个 shell。

4.6 停止和删除容器

容器生命周期管理:停止容器、删除容器。

停止容器运行。容器停止后,不代表容器被删除,只是"不运行了"。

bash 复制代码
docker stop day02-nginx

删除容器,需要先停止后,才可以删除。

bash 复制代码
docker rm day02-nginx

图形化界面也可以看到这个容器被删除了。

4.7 目录挂载

**最接近真实开发场景的一步:**把宿主机目录挂载到容器里,让容器直接使用本地的文件。

挂载是连接"本地开发"和"容器运行"的桥梁。

先准备一个本地目录:

bash 复制代码
cd ~/intern_pre/day02
mkdir -p docker_demo
echo '<h1>Hello from Docker bind mount</h1>' > docker_demo/index.html

然后启动容器:

bash 复制代码
docker run --name day2-web -d -p 8081:80 -v $HOME/intern_pre/day02/docker_demo:/usr/share/nginx/html:ro nginx

此时在浏览器访问 http://localhost:8081,可以正常访问:

尝试修改这个文件,重新写入会发现页面也发生了变化。

bash 复制代码
echo '<h1>Updated from host machine</h1>' > docker_demo/index.html
curl http://localhost:8081

测试完毕,可以将这个容器删掉了。

bash 复制代码
docker stop day2-web
docker rm day2-web

这一步和运行容器很相似,区别就在于:

-v 宿主机目录:容器目录:ro

这是挂载语法。

意思是:把宿主机目录映射到容器里的某个目录。

例如:

bash 复制代码
-v $HOME/intern_pre/day02/docker_demo:/usr/share/nginx/html:ro

表示:

  • 宿主机目录:docker_demo
  • 容器目录:/usr/share/nginx/html
  • ro:只读挂载

5. PyTorch 入门

今天已经练习挺多得了,PyTorch 的时间不是很多了,大概看几个视频就收尾得了。

这部分直接无脑小土堆了,大家都推荐的肯定没错:PyTorch深度学习快速入门教程(绝对通俗易懂!)【小土堆】_哔哩哔哩_bilibili

完整学习笔记直接参考这个博主:【Pytorch入门】小土堆PyTorch入门教程完整学习笔记(详细笔记并附练习代码 ipynb文件)-CSDN博客

5.1 Pytorch 的配置与安装

打开Anacanda并激活虚拟环境,下载pytorch:

然后测试一下是否可以正常使用:(我的电脑没有GPU所以安装的是CPU版本的)

5.2 Python 编辑器

准备好 Pycharm 和 Jupyter 即可。

在 Pycharm 中新建项目:

然后配置好解释器,测试一下当前环境是否可以正常使用 torch。

接下来准备 Jupyter 环境,很久没用了,先尝试打开:

但是这个环境和 pytorch 不互通,优先解决方案是在 pytorch 环境中再安装一遍 Jupyter,所以需要回到 pytorch 虚拟环境中下载对应的包:

bash 复制代码
#安装命令如下
pip install ipykernel

然后打开 jupyter 页面(我的没有显卡,返回 False 是正常的):

bash 复制代码
jupyter notebook

配置好之后,以后每次用的时候,只需要在 Anacanda 里面打开然后运行以下命令就可以了:

bash 复制代码
conda activate pytorch
jupyter notebook

今日份学习over ,撒花!

相关推荐
向上的车轮2 小时前
熟悉C#如何转TypeScript——SDK与包引用
开发语言·typescript·c#
蓝天守卫者联盟12 小时前
玩具喷涂废气治理厂家:行业现状、技术路径与选型指南
大数据·运维·人工智能·python
m0_738120722 小时前
我的创作纪念日0328
java·网络·windows·python·web安全·php
脆皮炸鸡7552 小时前
Linux开发工具~~~版本控制器Git以及调试工具GDB
linux·服务器·开发语言·经验分享·git·学习方法
無限進步D2 小时前
算竞常用STL cpp
开发语言·c++·算法·竞赛
red1giant_star2 小时前
浅析文件类漏洞原理与分类——含payload合集与检测与防护思路
python·安全
tryCbest2 小时前
Python之Flask开发框架(第一篇) — 从安装到第一个应用
开发语言·python·flask
q5431470872 小时前
Java进阶总结——集合
java·开发语言
啥咕啦呛2 小时前
java打卡学习5:java基础学习
java·开发语言·学习