小说剧情开端便是大家比较喜闻乐见的大型情色交易现场,后续的剧情似乎也变得清晰可见:老魏或者抛妻弃子、奔赴小三;或者狠心绝情、成为海王。虽然故事的发展并未像一些狗血剧情让读者感到三观破碎之类的震惊,但作者在这个过程中进行了大量心理、比喻、环境的描写,使得老魏情感的变化变得细腻可见、可听可感。读完细细想来,从“钱与色”的交易到“情与爱”的生活,究竟是什么造就了这个转变,又是什么迫使二人离别?
领略二人故事全貌后,则可按部就班从他们的背景出发。三十四岁的女人逢佳,让多年前抛弃她和母亲与别的女人去了香港的父亲帮助,移居香港,本想安定之后再接丈夫、儿子到港,“不料”第一年,她丈夫就跟她离婚去了美国。一则父亲在港“自顾不暇”,一则“也是为争一口气”,逢佳决意也要去美国,而由老乡小栉介绍认识了老魏。五十多岁的有妇之夫老魏是美国第二代移民,辛苦创下了家业,一年两度生意淡季便到香港度假。这二人都出身于艰苦的家庭环境,且都历经一番生活的磨砺,认清生活的真相。这是二人摩擦出“情”的基础,也是老魏没有选择凯弟的原因。事实上,将“商人包小三”的偷情故事描述为“情与爱”是困难的。就如同前几年上热搜的“牺牲卧底警察的女友爱上毒贩”的故事,这样不道德的恋爱关系总不会让人们理所当然的认同,甚至烦恶与唾骂。而二人的背景,尤其逢佳屡次被抛弃的经历,从她口中平静地讲出,再联想到她孤身一人在香港的夹缝中生存,又总会让人有淡淡的同情,渐渐就溶解了心中的成见。
接下来按照故事的发展进行梳理。虽然故事以“钱与色”为目的开篇,但给人的感觉并不浓烈:“老魏基本以隔天一次的节奏请逢佳吃晚饭或是喝酒。”就是不带逢佳回酒店———故事开始于老魏以追求者一般的方式持续地约会逢佳。显然,作为“交易”,这样的过程显得拖沓和奇怪。所以,逢佳跟小栉说:“老魏是个老滑头,不说行,也不说不行,却是三天两头地请她吃饭喝酒,她倒成了个陪酒的了。”但是,正是经由老魏刻意设计的这一“约会”式的开端,老魏和逢佳超出“情与色”自然地开始了。这其中固然有老魏的安排,但更离不开逢佳的配合。
另外,故事中多次提到“良心”,这之中的“良心”是很微妙的东西。老魏带逢佳买衣服时,注意到她挑选低调的款式,体会到她的世故和自尊,以及对他的关心。虽然两人关系是交易性质,但内心都保持了善意。这种“良心”使他们在朝夕相处中逐渐产生了真心。老魏再次到香港,住在逢佳的公寓,甚至买下一套房子,呈现出一种和谐的生活景象。最终,逢佳提出做老魏的“小老婆”,并一度陷入对彼此关系结果的思考,甚至尝试成为“第三者”。本该面目冷酷的交易的“甲方”老魏,则充满人情味地处处为逢佳感到心疼和怜惜。
最终,我们可以回答最初的问题了:二人的相遇逐渐演变成了一个情爱故事,并在“良心”的作用下,这段以金钱和色相为基础的关系转化为了一段“情与爱”的故事。在情感故事的模式和“良心”的引导下,我们很容易忽略其交易的本质,因为本来无关的两个人在不知不觉中产生了真情,这也证明了人与人之间情感的复杂和向善的力量。
Lab PHP
本文字数: 9.3k 阅读时长 ≈ 17 分钟
Lab_dataSolve
本文字数: 4.8k 阅读时长 ≈ 9 分钟
华东师范大学软件工程学院实践报告
实验课程:数据库系统实践 | 姓名:刘佳奇 | 学号:10225101455 |
---|---|---|
实验名称:Lab3 函数与存储过程 | 实验日期:2024/4/25 | 指导老师:姚俊杰 |
映像循回
本文字数: 357 阅读时长 ≈ 1 分钟
宇哥说他不再爱我了。
我们已数月没见。
但我闭上眼,仍能清晰勾勒出他的模样:高高壮壮,笑起来像一只痞坏的柴柴。
他的碎发里有一股过期的洗洁精的味道,但并不难闻。
不能再想下去了。我翻了个身,懊恼地想道。明早还有早八,中午还要给赵老师送份文件。已经四点十五了,抓紧时间多睡会,白天才能打起精神。
但我怎得落到这分田地?竟丧失了完好的睡眠,深夜里只能不由得黯然神伤,何至于此?
思索着,思念着,我昏厥了过去。
一觉醒来已是下午两点钟。刚刚爬起的张皓栋只觉神清气爽,便知大事不妙。偷偷打开手机瞄到时间后,栋桑长叹一声,浑身疲软,好像一个晚上的第八次(bushi;直直向床上倒去。闭眼神游了几秒,终于还是面对现实打开了手机。坚决执行电话-QQ-微信三步走战略,深度贯彻以老师为中心的发展思想,并启动究极生病备用计划确保栋桑的可持续发展。
浅谈车联网CAN总线安全(基于ICSim
本文字数: 5.8k 阅读时长 ≈ 11 分钟
我个人对车联网安全算是倾慕已久(bushi,想想吧,超巨型遥控车,属实有点酷炫。从另一个方面看,因物理意义上的人是确确实实坐在车里的,这和传统的虚拟战场攻防区别开,赋予了车联网安全特别的意义。
现代汽车产业发展迅速,传统汽车再满足不了人民日益增长的美好生活需要(最政治正确的一集。早期的车辆是没有电气系统的,发动机以及相关机械功能的工作都是纯机械驱动;没有空调,没有灯。但这样汽车永远只会是代步工具而无法满足驾驶员的驾驶体验。于是抛除掉基本的运载功能,各种子系统在不断增加,其中革命性的发展在20年代中期——电子控制单元(ECU)的出现,现代车辆已有数百个ECU,负责转向、加速、制动等等功能。1986年,德国公司Bosch开发出CAN总线来连接ECU。而在此之前,车载通信系统是通过点对点的布线系统实现的。随着车载电子元件越来越多,这种通信系统变得愈发笨重,而且维护费用非常昂贵。
对于CAN总线的安全性,由于这是一种低级协议,所以不存在内在的安全功能,所以其网络数据可以被任意截取。在大多数应用中,应用程序需要部署自己的安全机制,例如认证传入命令或网络上某些设备的存在。若不执行适当的安全措施,其他人可能设法在总线上插入消息。尽管一些安全关键功能(如修改固件,编程键或控制防抱死制动)存在密码,但这些系统并未普遍实施,并且密钥对的数量有限。
总的来说,CAN总线控制各种ECU怎么配合,即他们之间的通信。由此可以想象,如果有人能操控你的CAN总线进行命令控制,那是多么可怕的一件事。
防御措施
车载加密技术:车载加密技术可以对车辆明文数据信息进行保护,有效防止攻击者利用传输信道窃取或破坏传输信息,进而保证数据传输的完整性和机密性,避免数据泄露的安全风险。Aminifar
等提出了一种基于迭代分组密码的对称加密方法,并设置了机密保护与开销之间的权衡机制,以最大限度地提高机密性,同时保证实时性的要求。
车载防火墙技术:防火墙技术可以对网络流量进行监控,根据事先制定的安全策略对数据流量进行管控。Luo等为车载网络设计一个安全网关,基于威胁分析定义了车载网关的安全要求,提出将安全通信、密钥主控和防火墙作为保护汽车网关的安全机制,安全通信机制主要包含消息身份验证和数据加密。
车载入侵检测技术:相较于静态的车载入侵防御系统(intrusion prevention
system,IPS),车载入侵检测系统(intrusion detection
system,IDS)可以对网络流量进行监控,是一种在不影响网络性能前提下的主动防御手段,主要有基于异常IDS、基于签名IDS、基于规范IDS、基于混合IDS、基于指纹
IDS、基于参数监控 IDS、基于信息熵IDS 和基于机器学习 IDS。其中,基于异常
IDS为业内常用的入侵检测方法,将实时数据与正常行为数据进行比对,利用训练好的模型分析结果和常规值的偏差与阈值之间的关系,定位安全风险。
车载安全审计技术:利用车载终端记录的访问日志进行审计和监管,也是车载终端系统安全防护的重要手段之一。Checkoway
等通过实验验证了审计系统会在发现异常或攻击事件时启动处理程序,降低潜在攻击的威胁。常见的安全审计方法有基于数理统计的安全审计、基于特征匹配的安全审计以及基于预测感知的安全审计。
车载网络安全认证技术:车载网络安全认证技术可以增强车载系统的安全性。Jo
等提出了一种Mauth-CAN认证方法,利用ECU与验证器共享密钥,验证器可以安全有效地为ECU分配种子值,进而规避由ECU发起伪造攻击的安全风险。
仿真环境与基本操作
ICSim
./setup_vcan.sh # 初始化,每次重启后都要重新运行
./icsim vcan0 # 仪表界面
./controls vcan0 # 控制界面
其中启动 setup_vcan.sh 主要功能是加载CAN和vCAN(virtual controller area network)网络模块。并创建名为vcan0的网络设备打开连接。
功能 | 按键 |
---|---|
加速 | 上方向键 |
左转向 | 左方向键 |
右转向 | 右方向键 |
开/关左车门前锁 | 右/左shift + A |
开/关右车门前锁 | 右/左shift + B |
开/关左车门后锁 | 右/左shift + X |
开/关右车门后锁 | 右/左shift + y |
开启所有车门锁 | 左shift + 右shift |
关闭所有车门锁 | 右shift + 左shift |
can-utils
sudo apt-get install can-utils
这是一个用于控制与 CAN 总线通信的工具集合,具体包括如下:
cansend:用于向 CAN 总线发送单个 CAN
帧。可以指定帧的标识符、数据和其他参数。
candump:用于监听 CAN
总线上的数据帧,并将接收到的帧显示在终端上。可用于实时监测 CAN
总线的数据流。
canplayer:用于回放记录在文件中的 CAN 数据帧。可以模拟之前捕获的 CAN
数据,对系统进行测试和验证。
cangen:用于生成随机的 CAN 数据帧,用于测试和模拟不同的 CAN
数据场景。
cansniffer:用于监视 CAN 总线上的数据帧,并将其显示在终端上。与 candump
不同的是,cansniffer
可以提供更详细的信息,如错误检测和计数器统计等。
canbusload:用于测试 CAN 总线的负载容量。通过生成大量的 CAN
数据帧,可以评估 CAN 总线的性能和稳定性。
socketcand
用于在Linux系统上实现CAN(Controller Area Network)总线的通信。它提供了一个简单且灵活的接口,使用户能够通过套接字(sockets)与CAN总线进行通信。我们需要用这个工具来让SavvyCAN跟CAN总线通信。
下载socketcand
git clone https://github.com/linux-can/socketcand.git
cd socketcand
获取缺少的文件
wget https://raw.githubusercontent.com/dschanoeh/socketcand/master/config.h.in
编译安装
autoconf
./configure
make clean
make
sudo make install
SavvyCAN
SavvyCAN是一个基于多个QT平台的C++程序,主要用于CAN数据的逆向分析和捕获。
# 直接下载二进制文件进行使用
wget https://github.com/collin80/SavvyCAN/releases/download/continuous/SavvyCAN-1999da8-x86_64.AppImage
chmod 777 SavvyCAN-1999da8-x86_64.AppImage
./SavvyCAN-044fea3-x86_64.AppImage
```
需先安装[Qt5环境](https://download.qt.io/archive/qt/5.14/5.14.2/),注意安装时不能只安装Qt creator,全部下下来内存还挺大的,大约五六个G,注意留好空间。
然后在 Connection->Open Connection Window->Add New Device Connection 中选择 QT SerialBus Devices,将 SerialBus Devices 选择为 socketcan,将port选择为虚拟端口vcan0,就可以开始捕捉与过滤了。
## WireShark
无处不在
# 如何物理意义上接入CAN网络
通过OBD可以直接访问CAN。车上诊断系统(On-Board Diagnostics),是一种装置于车中以监控车辆运行状态与回报异常的系统,可于车辆的子系统出现问题时,产生故障代码和提醒讯号通知车主和车厂诊断维修。
示例位置:[江铃车系的OBD诊断接口](https://www.bilibili.com/video/BV1xh411Q7AP/?spm_id_from=333.337.search-card.all.click&vd_source=925702a604089f3c4965c6447751f6ed)
得知车辆的大概布线的话,可以从锁着的车外卸下铁皮,从外部接入OBD的布线。
# 重放攻击
重放攻击(Replay attack)是一种网络攻击,指攻击者发送一个目的主机已接收过的包,来达到欺骗系统的目的,主要用于身份认证过程,破坏认证的正确性。攻击者利用网络监听或者其他方式盗取认证凭据,之后再把它重新发给认证服务器。从这个解释上理解,加密可以有效防止会话劫持,但是却防止不了重放攻击。重放攻击任何网络通讯过程中都可能发生。
在仿真模拟中,可利用can-utils中的candump与canplayer工具来实现数据包的捕捉与重放。
candump -l vcan0 # 将数据包存储到log中 canplayer -I 文件名.log # 进行重放攻击
危害举例:车辆跟充电桩之间的通信部分也是CAN通信,如果CAN流量能够进行重放,没有一定的防御机制,那么攻击者可能可以通过这种方式进行恶意扣费等操作,即捕捉你付费的数据包重复发送。
加速正常重放只能加速一下,写一个python程序:
import os import time
while True: os.system("cansend vcan0 244#0000003894") time.sleep(1)
# 消息逆向
虽然流量重放能够让我们触发特定的操作,但实际上我们不知道是哪一帧能够触发这个操作,这就需要我们对消息进行逆向。根据抓取的CAN数据还原其外在的体现,具体分析指令对应的功能。CAN 总线命令的语义通常可分为两类:(1) 控制,它操作车辆的物理部件,如解锁车门和启动发动机;(2) 诊断,用于查询车辆的数据(如速度和温度)。对于每个语义含义,都有一个对 CAN 总线命令的一对一映射。例如,对于丰田普锐斯,CAN总线命令标识符"0x750"是指主体,"0x7C4"用于空调。
这里随便举个例子来说明其具体格式
(1714014624.483285) vcan0 19B#000000000000 # 对应 (时间戳)
can接口 仲裁ID#数据 # 仲裁ID的数字越低,在网络上的优先级就越高。
分析数据可以根据log文件慢慢排查,就是删删删(二分法)不停运行看到底是哪行负责。第一次获取log文件手慢了直接获取了一万六千多行...找不了一点,后面手快缩短到五千行,但也二分了19次才找到。
快一点的方法就是利用cansniffer工具看动态的log,即操作一下看看是哪些数据在变化,但咱属实眼神不好...(Bushi。就不放静态的图了,因为动态的看一下还蛮明显的,以开车门举例,可以明显发现进行开车门操作时多了一行数据。
cansniffer -c vcan0
另外,SavvyCAN中的sniffer要更好找一些,开启notch过滤直接世界都清净了。
# 基于CAN总线协议仲裁机制的DOS攻击
一句话概括CAN总线的机制:CAN总线是一种基于“先来后到、无损仲裁”机制、多主(无主)结构、具有帧ID、应用数据最多8个字节、采用差分电平的国际标准现场总线。细细说来,“先来后到”是说总线空闲时,任何一个CAN节点都可以发送数据,谁先来谁先发,避免内卷,从我做起,哦耶。“无损仲裁”是说两个节点同时发的时候,则比较数据帧ID部分来决定谁先发送,ID小的先发,ID大的自动退出。而退出后数据也不会丢失,而是等待下一个空闲期再尝试发送。“多主”指每个节点的地位相对来说是平等,都可以主动发起数据。
这里可能会发现这个机制和p-坚持CSMA有些类似,但又稍有不同。其一,CSMA碰了再改,CAN先比再发。当多个节点监听到信道为空闲时,CSMA可能同时发送数据而导致碰撞,然后等待随机时间再发送;CAN中尝试发送前会先比较。其二,CSMA如果发生碰撞,数据可能丢失;CAN即使发生碰撞,数据也不会丢失。另外,简要分析一下这样设计的原因,CSMA粗糙一些,目的是网络中的节点共享通信信道,主要希望减少碰撞而增加网络的吞吐量和效率;CAN精细一些,目的是提供可靠的实时通信,主要希望保证数据的准确性。
我们先找到两个低优先级的操作,为了做对比实验
cansend vcan0
19B#00000E000000 # 开车门 cansend vcan0 19B#00000F000000 # 关车门 #
找一个高于他们的,这里使用的左转向灯 cansend vcan0 188#01000000 #
开左转向灯
#include <stdio.h> #include
<stdlib.h> #include <unistd.h> #include
<pthread.h>
void* send_message(void* arg) { while (1) { system("cansend vcan0 188#01000000"); }
return NULL;
}
int main() { pthread_t threads[100];
for (int i = 0; i < 100; i++) {
pthread_create(&threads[i], NULL, send_message, NULL);
}
while (1) {
sleep(1);
}
return 0;
}
这段代码的作用是创建了100个线程,每个线程都会不断地向CAN总线发送相同的消息,模拟了多个节点同时发送数据的情况。
gcc -o attack main.c -pthread ```
编译为attack可执行文件后执行,发现左转灯一直在开。随后利用模拟器进行开关车门的操作,会发现好几次之后才成功。所以只能是造成部分CAN数据干扰,不能百分百干扰,不过还是可以感觉到是有变化的,部分数据会产生丢失,造成对应的指令没有执行成功。
MySQL Lab_2 函数与存储过程
本文字数: 7.8k 阅读时长 ≈ 14 分钟
华东师范大学软件工程学院实践报告
实验课程:数据库系统实践 | 姓名:刘佳奇 | 学号:10225101455 |
---|---|---|
实验名称:Lab2 函数与存储过程 | 实验日期:2024/4/18 | 指导老师:姚俊杰 |
从零开始的妙趣经济学之路
本文字数: 1.1k 阅读时长 ≈ 2 分钟
故事的开始......一门伪装为通识课的妙趣经济学,实则是张牙舞爪的经济学原理。(发出尖锐的爆鸣声
那么,为了将全世界的米都收入囊中,实现海洋公主的复仇之路,Link
Start!
经济学是研究什么的?如何分配社会的稀缺资源,而非是仅仅局限于狭义的“经济”二字。
经济学十大原理
原理9:当政府发行了过多货币时,物价上升。
原理10:社会面临通货膨胀和失业之间的短期权衡取舍。这个原理可以用来解释商业周期,即经济活动(就业机会、生产活动)中出现的波动。注意是短期,从长期来看,货币数量只影响通货膨胀(原理9),失业和货币数量无关。
供给与需求的市场力量
市场是什么?市场是由某种产品或服务的买方与卖方组成的一个群体。市场的类型有很多,如完全竞争市场(产品相同,买卖双方人数众多,且都不能影响市场价格,大家都必须接受市场上确定的价格,都能买到或出售任意数量货物,不会因为你要买一百个保温壶保温壶就涨价了,相当于一种理想模型),垄断市场(市场上只有一个卖方,价格他说了算,比如专利版权),寡头垄断市场(市场内卖方数量少且并非总是积极的竞争,如可口和百事),垄断竞争市场(市场内许多卖家且有差异化产品,可以自己定价,如电子游戏,餐馆米其林一星二星三星,是有一点子market_power在的)。
## 需求
经济学中的需求与我们认知中的区别是关注了你的购买力,定义为买方愿意购买且能够购买的产品的数量。所以比方说如果冰淇淋白送你的需求量是十二个,涨价到三元你的需求量变为0个。此为个人需求,市场需求则为市场内个人需求对应求和。
对于需求曲线,重点区分需求曲线移动与沿着需求曲线移动,只有当价格变化时,如税率,才会表现为沿着,其余比如买方数量变化等都是直接使需求曲线移动。
其余情况:
正常产品的需求与收入成正比:收入增加会增加每种价格水平下的需求量,并使需求曲线向右移动
(低档产品的需求与收入成反比,收入增加会使低档产品的需求曲线向左移动)
假如手机壳价格上升,对手机的需求会有什么影响? E
A. 沿着需求曲线上移
B. 沿着需求曲线下移
C. 需求曲线左移
D. 需求曲线右移
E. 以上都不是
这里这道题明显是个坑,谁买手机之前会先查查手机壳涨没涨价?他们并不是诸如电脑和软件、羽毛球与羽毛球拍之类的互补品。
供给
经济学中的“供给”同样与我们认知中的略有差异,定义为卖方愿意并且能够出售的产品的数量。区分需求与供给,还以冰淇淋为例子,冰淇淋供给量越多,价格越会上升(卖家越愿意卖,注意定义对卖家意愿的注重,如果市场上冰淇淋免费送,谁还去当大怨种做慈善...)。
价格弹性
神秘的“造物” ——矛盾《创造》
这篇小说联合茅盾个人的经历投射出当时一种典型的时代故事,传承至今演变为脍炙人口的“养成系”。
一、作者态度的展示与引导
读小说时通过作者的用词便可以辨别作者的态度,茅盾并不是一个吝惜于表露自己态度的人。如本小说中使用“保守思想,指桑骂槐”等来形容可看出作者对君实的讽刺。
娴娴说君实说话时的神气使她难受(间接引语)
君实说话时的神气使她难受(自由间接引语),这样既可以看为娴娴的态度,又可以看为作者的态度。詹姆斯伍德:我们同时拥有全知视角和限知视角。很直接的一个结果:会引导读者的态度,产生与描述的对象没有任何隔膜的错觉。
二、“创造”、“恋爱”与“革命”
“创造”,“新”,“变化”在那个新文化时代被赋予别样价值,是毋庸置疑的褒义词,相应得“旧”非常不好,如果回到那个年代谈“怀旧”,一准会被疯狂鄙视。
在那个年代,“革命家恋爱”模式(光荣的“流行病”)被推崇,二者互相辉映。“创造”、“恋爱”与“革命”三个词是互文的关系,相互包含,爱情中总是包含了一种创造的预期。在小说中,君实便含了这样一种理想,但最后他二者都失败了,他所创造的娴娴脱离了他的控制。他监控了整个创造的过程,“我真不知道是怎么一回事,我不相信书里的真理会有两个”,类似于数学公式与化学实验,但人要复杂的多。他渴望着双重的收获,但最后他失去了爱情与革命的动力。“黄道士烧符念咒的时候,唯恐鬼不来,等到鬼当真来了,他又怕的跟什么似的,心里抱怨那鬼太狞恶,不是他的理想的鬼了”,娴娴却觉君实所谓数学公式只是装神弄鬼。“君实轻轻的拉下了娴娴的手,细珍珠给他的手指一种冷而滑的感觉。他的心灵突然一震”一个自己相识多年很熟悉的人,在某个瞬间自己却觉得对方陌生无比,刻画了这样一个场景。最熟悉的东西突然变成最陌生的东西,给人的恐惧感很强烈(一些恐怖片让家人变成阿飘)uncanny,形容熟悉突然感到陌生,弗洛伊德在心理学上有具体的解释。
弗兰肯斯坦:人造人,非常丑陋,创造他的科学家被吓跑。娴娴:也可以看作是由知识的碎片来拼凑
参考资料: 1. 茅盾:创造一个爱人和同志
“逃离大城市”or“逃回大城市”
“逃”之一字,让许多人目之所及便心有戚戚,心觉自己所处竟落得这样的凄惨!事实上,问题应当出在社会环境之中,并不是单纯你决定今晚吃什么。城市与乡村均有其局限性,好似两个嗷嗷待侍寝的丑逼,一位一个月没洗澡,一位细如萝卜丁,just choose。两害相权取其轻,让我们进入萝卜丁的世界扒。 身处大城市,压力大属于是公认的臭蛋了。精神压力上(高贵的分类语句),通勤时间长,工作时间长,拉屎时间也很长。(才没有带薪xx呢!口亨!)不知名x杨giegie透露,硕士毕业工作一年,最bk的就是自己的时间太少了。(虽然说他是一个有双休的凡尔赛天后)
从两数之和开始的力扣通关之路
本文字数: 2.8k 阅读时长 ≈ 5 分钟
1. 两数之和
class Solution:
def twoSum(self, nums: List[int], target: int) -> List[int]:
hash_table = {}
for i in range(len(nums)):
# for i,num in enumerate(nums):
diff = target - nums[i]
if diff in hash_table:
return [hash_table[diff],i]
else:
hash_table[nums[i]] = i
return []
11. 盛水最多的容器
class Solution:
def maxArea(self, height: List[int]) -> int:
max_area = 0
left = 0
right = len(height) - 1
while left < right:
current_area = min(height[left], height[right]) * (right - left)
max_area = max(max_area,current_area)
if height[left] < height[right]:
left += 1
else:
right -= 1
return max_area
最大肯定宽度得大,从两边开始往中间合拢。(直观想法)想想为什么从头往后拓宽不行,典型错例比如[1,2,1],初始化left=0,right=1,1 < 2,left也到2,相同然后left再+1到1,没有遍历出1和1相差2这种情况。所以两头才是所有的情况而从头会有遗漏。两边一边一个指针,谁小谁挪,每次记录一下最大面积。
错误代码be like:
class Solution:
def maxArea(self, height: List[int]) -> int:
max_area = 0
left = 0
right = 1
while left < len(height) and right < len(height):
current_area = min(height[left], height[right]) * abs(right - left)
max_area = max(max_area,current_area)
if height[left] <= height[right]:
left += 1
else:
right += 1
return max_area
15. 三数之和
49. 字母异位词分组
class Solution:
def groupAnagrams(self, strs: List[str]) -> List[List[str]]:
anagrams = {}
for s in strs:
sorted_s = ','.join(sorted(s))
if sorted_s in anagrams:
anagrams[sorted_s].append(s)
else:
anagrams[sorted_s] = [s]
return list(anagrams.values())
128. 最长连续序列
思路一
class Solution:
def longestConsecutive(self, nums: List[int]) -> int:
if not nums:
return 0
consecutive_map = {}
max_length = 0
sorted_nums = sorted(nums)
for n in nums:
if n in consecutive_map:
continue
left_length = consecutive_map.get(n - 1, 0)
right_length = consecutive_map.get(n + 1, 0)
current_length = left_length + 1 + right_length
consecutive_map[n] = current_length
max_length = max(max_length,current_length)
consecutive_map[n - left_length] = current_length
consecutive_map[n + right_length] = current_length
return max_length
1,最大长度是1,左看看有看看,2,左边有1,最大长度是2,更新一下1的节点,以此类推。
思路二(官方题解
class Solution:
def longestConsecutive(self, nums: List[int]) -> int:
longest_streak = 0
num_set = set(nums)
for num in num_set:
if num - 1 not in num_set:
current_num = num
current_streak = 1
while current_num + 1 in num_set:
current_num += 1
current_streak += 1
longest_streak = max(longest_streak, current_streak)
return longest_streak
将List转换为Set,Set与List类似,但不存储相同的元素,且查找速度要更快一些。先找到连续序列的开头,然后再用循环往下找最长序列。
283. 移动零
class Solution:
def moveZeroes(self, nums: List[int]) -> None:
"""
Do not return anything, modify nums in-place instead.
"""
left = 0 # left用来指示0的位置
right = 0 # right用来遍历数组
while right < len(nums):
if nums[right] != 0:
nums[left],nums[right] = nums[right],nums[left]
left += 1
right += 1
1,0,2,最开始left,right都指1,1不是0,1和自己换一下,然后left和right都+1,都指0,0等于0不执行if语句,只有right继续遍历+1,left指向0,标识0的位置。right指向2,执行if语句,将0和2换位,跳出while循环结束。