ARTS第八周
1.Algorithm:每周至少做一个 leetcode 的算法题
2.Review:阅读并点评至少一篇英文技术文章
3.Tip:学习至少一个技术技巧
4.Share:分享一篇有观点和思考的技术文章
以下是各项的情况:
Algorithm
题意:
给定一个包含 n 个整数的数组 nums 和一个目标值 target,判断 nums 中是否存在四个元素 a,b,c 和 d ,使得 a + b + c + d 的值与 target 相等?找出所有满足条件且不重复的四元组。
给定数组 nums = [1, 0, -1, 0, -2, 2],和 target = 0。
满足要求的四元组集合为:
[
[-1, 0, 0, 1],
[-2, -1, 1, 2],
[-2, 0, 0, 2]
]
分析:
类似三数之和 , 外层多一层循环
class Solution {
public List<List<Integer>> fourSum(int[] nums, int target) { List<List<Integer>> result = new ArrayList<>();
//先排序
Arrays.sort(nums); for (int i = 0;i < nums.length - 2;i ++) {
// 去除指针i可能的重复情况
if (i != 0 && nums[i] == nums[i-1]) {
continue;
}
for (int j = i + 1;j < nums.length;j ++) {
// 去除j可能重复的情况
if (j != i + 1 && nums[j] == nums[j-1]) {
continue;
} int left = j + 1;
int right = nums.length -1; while (left < right) {
// 不满足条件或者重复的,继续遍历
if ((left != j + 1 && nums[left] == nums[left-1]) || nums[i] + nums[j] + nums[left] + nums[right] < target) {
left ++;
} else if ((right != nums.length -1 && nums[right] == nums[right + 1]) || nums[i] + nums[j] + nums[left] + nums[right] > target) {
right --;
} else {
List<Integer> list = new ArrayList<>();
list.add(nums[i]);
list.add(nums[j]);
list.add(nums[left]);
list.add(nums[right]); result.add(list);
// 满足条件的,进入下一次遍历
left ++;
right --;
}
} }
} return result;
}
}
Review
分享 写伪代码来帮助理清思路 https://www.geeksforgeeks.org/how-to-write-a-pseudo-code/
如何写一个伪代码?
伪代码是经常用于编程和基于算法的字段的术语 。它是一种允许程序员表示算法实现的方法。简单地说,我们可以说它是算法的显性表示 。通常,算法在伪代码的帮助下表示,因为无论什么编程背景或知识等级,程序员都可以解释它们 。顾名思义,伪代码是一种假代码或代码的表示,即使是具有一些学校级编程知识的外行也可以理解 。
算法:它是有组织的逻辑序列或针对特定问题的方法 。程序员实现一种算法来解决问题。算法使用自然语言但有些是用注释来表达 。
伪代码:它只是以简单英语编写的注释和信息文本形式的算法实现 。它没有任何编程语言的语法,因此无法由计算机编译或解释 。
Tip
为什么一般数组都是从0开始编号?(重温数据结构)
首先 重温数组概念 :
1. 数组(Array)就是一种线性表数据结构,用一组连续内存空间来存储一组具有相同类型的数据 。
线性表结构 : 数组,链表,队列,栈 非线性表 : 比如二叉树,堆,图等
2. 连续的内存空间和相同类型的数据
因为这两个特性或者说是限制,拥有一个性质 : “随机访问”。 顾名思义 , 可以随机地去访问数据 , 但相应的, 让数组的很多操作变的非常低效, 比如想在数组中删除,插入一个数据 , 运气不好就必须后移大量数据 。
拓展 : 因为当插入一个新元素时,如果插入末尾,那么此时时间复杂度为O(1),所以如果要将某个数组插入到第K个位置,为了避免大量的数据迁移,我们有一个简单的方法就是:直接将第K位置数据搬移到数组的最后,把新元素直接放入到第K个位置 。 这种处理思想也会在快速排序中使用到 。
同理 , 删除操作 , 比如数组A[10]删除前三个元素 , 为了避免后面元素要搬移三次 ,我们可以先记录下已经删除数据 . 每次删除操作并不是真正的搬移数据,只是记录数据已经被删除 。 当数组没有更多空间去存储数据时候, 我们才
触发真正的删除操作 , 删掉前三个元素 , 剩下原数组其他元素向前移动三个位置 即可 。 而这种思路正是JVM标记清楚垃圾回收算法的核心思想 。
其次 我们需要警惕数组的访问越界问题
例如 : 下面一段C语言代码 乍看上去没有问题
int main(int args,char* arg[])
{
int i = 0 ;
int arr[3] = {0};
for(; i<=3 ; i++)
{
arr[i] = 0;
printf("hello world\n");
}
return 0 ;
}
看起来会是输出三次hello world , 实际上是无线循环打印hello world ,这是为什么 ?
实际因为 数组大小为3 : A[0] , A[1 , A[2] 。 而代码中for循环的结束条件写成了 i<=3 而非 i<3 , 导致当i=3时候 , A[3]访问越界 。 C 语言中 , 只要不是访问首先的内存 ,所有的内存空间都是可以自由访问的 。 根据数组寻址公式 , A[3]也会被定为到某块不属于数组的内存地址上 , 而这个地址如果正好是存储变量 i 的内存地址 , 那么A[3]=0 就相当于 i=0 , 就会导致代码无限循环 。
数组越界在C语言是因为没有规定数组访问越界时候 , 编译器应该如何处理 。因为 ,访问数组的本质就是访问一段连续内存 , 只要数组通过偏移计算得到的内存地址可用 , 那么程序就可能不会报任何错误 。 而JAVA就不会像C一样 , 把数组检查的工作丢给程序员去判断 , 也因此会出现我们日常中头疼仅次于java.lang.NullPointerException: null 的 错误异常 : java.lang.ArrayhIndexOutOfBoundsException 。
比如 这段代码 :
int[] a = new int[3];
a[3] = 10 ;
就会抛出java.lang.ArrayhIndexOutOfBoundsException
最后 回到提出的问题 : 这些都了解后 就可以来思考 为什么数组要从0开始编号 , 而非从1 ?
从数组的内存模型来看 , 下标意味着"偏移"(offset) 。如果用 A 来表示数组的首地址 , A[0] 代表偏移为0 的位置 , 即是首地址 ,而 A[K] 就代表偏移K个type_size的位置 ,所以 计算 A[K]的内存地址 :
A[K]_address = base_address + K * type_size
但是从1开始计数的话 , 计算 A[K]的内存地址 的公式就变为 :
A[K]_address = base_address + (K-1) * type_size
从1开始编号 , 每次随机访问数组元素都多了一次减法运算 , 对于 CPU 来说 , 就是多了一次减法指令 。 为了提高效率 , 减少这一次不必要的减法操作 , 数组从0 开始编号变成约定俗成的 ,甚至是默认的规则 。 另一方面也是因为历史原因 : C语言设计就是从0开始编号 ,其他语言为了减少程序员学习难度就直接照搬 。 实际上, 虽然大多数编程语言 都默认数组从0开始 , 但还是有不少例外的 , 例如 python 就支持负数下标 (但数组下标仍然默认从0开始记数 , 举这个例子是为了说明虽然Python从功能上可以支持默认从负数下标开始 , 但为了减少学习难度 还是从0开始) , MATLAB 就是从1开始计数 。
Share
这周没看到什么有趣或者感觉实用的观点 , 以后补 。
ARTS第八周的更多相关文章
- ARTS 第八周打卡
Algorithm : 做一个 leetcode 的算法题 13. 罗马数字转整数 罗马数字包含以下七种字符: I, V, X, L,C,D 和 M. 字符 数值 I ...
- 第八周PSP
团队项目PSP 一:表格 C类型 C内容 S开始时间 E结束时间 I时间间隔 T净时间(mins) 预计花费时间(mins) 讨论 讨论用户界面 8:40 11:40 35 60 70 分析与 ...
- Java第八周学习总结
20145113第八周学习总结 第十五章学习内容 第15章比较琐碎,相对于之前章节也比较枯燥无味看了一部分,也动手敲了些 Logger logger = Logger.getLogger(" ...
- 补交作业-第八周PSP
一.表格 C(分类) C(内容) S(开始时间) ST(结束时间) I(打断时间) △(净工作时间) 讨论 用户界面 9:30 10:40 15 55 编码 编码 13:20 16:30 10 180 ...
- 20145213《Java程序设计》第八周学习笔记
20145213<Java程序设计>第八周学习笔记 教材学习内容总结 "桃花春欲尽,谷雨夜来收"谷雨节气的到来意味着寒潮天气的基本结束,气温回升加快.刚出冬的我对于这种 ...
- 20145304 Java第八周学习报告
20145304<Java程序设计>第八周学习总结 教材学习内容总结 NIO NIO使用频道来衔接数据节点,在处理数据时,NIO可以让你设定缓冲区容量,在缓冲区中对感兴趣的数据区块进行标记 ...
- 20145330第八周《Java学习笔记》
20145330第八周<Java学习笔记> 第十五章 通用API 通用API 日志:日志对信息安全意义重大,审计.取证.入侵检验等都会用到日志信息 日志API Logger:注意无法使用构 ...
- 20145337《Java程序设计》第八周学习总结
20145337<Java程序设计>第八周学习总结 教材学习内容总结 15.1日志 15.1.1日志API简介 使用日志的起点是logger类,logger实例的创建有许多要处理的要素,必 ...
- Linux内核设计第八周 ——进程的切换和系统的一般执行过程
Linux内核设计第八周 ——进程的切换和系统的一般执行过程 第一部分 知识点总结 第二部分 实验部分 1.配置实验环境,确保menu内核可以正常启动 2.进入gdb调试,在shedule和conte ...
随机推荐
- synchronized 的超多干货!
前言 synchronized 这个关键字的重要性不言而喻,几乎可以说是并发.多线程必须会问到的关键字了.synchronized 会涉及到锁.升级降级操作.锁的撤销.对象头等.所以理解 synchr ...
- Go语言网络通信---TCP通信上传一个小文件
server: package main import ( "fmt" "net" "os" ) func SHandleError(err ...
- 巧用Reflections库实现包扫描
1.需求 需要扫描某个包中的某个接口的实现类的需求 2.maven 依赖引入 <dependency> <groupId>org.reflections</groupId ...
- Javascript和Typescript语言类型
静态语言(强类型语言) 静态语言是在编译时变量的数据类型即可确定的语言,多数静态类型语言要求在使用变量之前必须声明数据类型. 例如:C++.Java.Delphi.C#等. 动态语言(弱类型语言) 动 ...
- 结构感知图像修复:ICCV2019论文解析
结构感知图像修复:ICCV2019论文解析 StructureFlow: Image Inpainting via Structure-aware Appearance Flow 论文链接: http ...
- 从PyTorch到ONNX的端到端AlexNet
从PyTorch到ONNX的端到端AlexNet 这是一个简单的脚本,可将Torchvision中定义的经过预训练的AlexNet导出到ONNX中.运行一轮推理Inference,然后将生成的跟踪模型 ...
- CUDA统一内存分析
CUDA统一内存分析 PascalMIG 如 NVIDIA Titan X 和 NVIDIA Tesla P100 是第一个包含页 GPUs 定额引擎的 GPUs ,它是统一内存页错误处理和 MIG ...
- fiddler选项卡-Statistc(统计)
Statistc Statistc是fiddler用来对session列表里的Session相关情况的统计,利用这个选项,可以对请求进行性能以及其他数据分析 1.界面 2.参数详解 建议:打开fidd ...
- 剑指 Offer 05. 替换空格
链接:https://leetcode-cn.com/problems/ti-huan-kong-ge-lcof/ 标签:字符串 题目 请实现一个函数,把字符串 s 中的每个空格替换成"%2 ...
- WordPress安装篇(3):用宝塔面板在Linux上安装WordPress
前面的文章已经介绍了如何在Windows环境安装WordPress,这篇文章来介绍在Linux环境怎样快速安装WordPress.大家都知道,Linux系统相对于Windows系统而言占用资源更少.更 ...