武汉加油,中国加油。希望疫情早日结束。

  由于疫情,二狗寒假在家不能到处乱逛,索性就在家里系统的刷一下算法的内容,一段时间下来倒也有些小小的收获。只是一来家中的小破笔记本写起博客来实在不是很顺手,二来家中吃喝玩乐的诱惑也不少了,就连着几天没有更新,惭愧惭愧。看来2020年还是要加强自己计划的执行能力。

  每个人都有适合自己的学习方式。虽然也挺喜欢看书,但对我来说,在学习新内容,不熟悉的内容的时候单纯的啃课本还是有些事倍功半,尤其是像算法这种这么容易看得一脸懵逼的内容。大名鼎鼎的《算法导论》买回来了挺长时间了,只看了感兴趣的几章,并且在看得时候经常怀疑自己,我是不是脑子不行啊,要不转行算了(苦笑)。基于之前学习数据库的经验,趁着寒假整了个算法的音频课程听了一下,感觉还不错,恩,看来我比较适合这种方式吧。以后再要学习什么新东西的时候记得提醒自己,先选对了学习的方式哈。

  女朋友问我,算法是什么,学这个有啥用? 其实之前我也没有想明白,最开始从leetcode刷题目的很简单,多长点见识,万一面试用上了呢。所以女朋友这么问的时候我就随口一胡扯:武功知道吧,之前的实战经验算是身法,这玩意儿(算法)是心法。现在对这个抖机灵的回答还有点小骄傲,我还挺机智的呀。可不是嘛,各种常见的数据结构,常见的算法,各大高级语言都帮我们实现好了,大家日常“CRUD”哪里用得上这些啊?但其实也不对,比如两种数据结构都可以做的时候,哪种更合适呢?如果想效率更高呢?如果必须要在限制的空间内完成呢?或者接地气一点:和同事关于内容battle的时候,怎么优雅地说服他呢?

来点干货:

  反正博客写给自己看,记录一下这两天笔记中让我有耳目一新的感觉的内容吧。

  数组:

  • 数组是一种线性表数据结构。它用一组连续的内存空间,存储一组具有相同类型的数据,最大的特点是支持随机访问
  • 根据下标来随机访问数组中的元素,所以数组这种结构的”查找“其实很高效。
  • 又因为它是连续存储的,所以相对来说,”插入“和”删除“这两个操作会比较低效。因为这两个操作很有可能使得数组内大量元素重新移动位置。
  • 因为是连续的内存空间,所以如果内存中剩下一个40m的内存块,一个60m的内存块,其实是无法申请一个80m大小的数组的。但是链表可以。

  链表:

  • 与数组相反,链表不需要连续的内存,它通过”指针“来将一组零散的内存块串起来使用。所以上面数组中的那种情况,链表是可以完成的。
  • 相对数组来说,链表的”插入“和”删除“会高效很多,毕竟只要改变相关联的指针的指向即可。

  这两种数据结构实在是太基础了,基础到基本不会用到。拿二狗子来说,如果有类似的东西需要实现的话我会怎么做呢,我会申请一个List出来,剩下的都交给List去做了。但看看上面两中数据结构的比较,其实差别还是挺大的。而关于List,写这篇博客的时候我又去微软官方文档瞅了一眼:

  • List<T>类是 ArrayList<T>类的泛型等效项。 它通过使用大小根据需要动态增加的数组来实现IList<T>泛型接口。
  • 在决定是使用List<T> 还是 ArrayList类(两者都具有类似的功能)时,请记住List<T> 类在大多数情况下性能更佳并且是类型安全的。 如果引用类型用于 List<T>类的类型 T,则这两个类的行为是相同的。 但是,如果将值类型用于类型 T,则需要考虑实现和装箱问题。

  • 如果值类型用于类型 T,则编译器将为该值类型专门生成 List<T>类的实现。 这意味着,在使用元素之前,不需要对 List<T>对象的 list 元素进行装箱,在创建了大约500个列表元素后,不会对其进行装箱的内存列表元素大于用于生成类实现的内存。

  看来,List应该是用数组来实现的,并且.net有一些特殊的处理使得这家伙既安全,又高效。至于第三条,看来如果要存储的是值类型的数据,并且数据量较多的情况下还是使用List比较高效。另外微软也是建议大家尽量使用List而不是自己手动实现,原因如下:

  使用 List<T> 类的特定于类型的实现,而不是使用 ArrayList类或自行编写强类型包装集合,这一点非常有利。 原因在于,你的实现必须执行 .NET Framework 的操作,并且公共语言运行时可以共享你的实现不能的 Microsoft 中间语言代码和元数据。

 

  栈

  后进者先出,先进者后出,是一种”操作受限“的线性表。

  队列

  先入队列的先出队列,后入的后出。同样,队列也是一种”操作受限“的线性表。

  这两种数据机构也很常见,新的发现是在做练习时遇到了这样一道题,怎么用栈来实现一个队列,题目不难,但是挺有趣的。贴一下题目与笔者的做法,题目来源于Leetcode。

232. 使用栈实现队列的下列操作:

push(x) -- 将一个元素放入队列的尾部。
pop() -- 从队列首部移除元素。
peek() -- 返回队列首部的元素。
empty() -- 返回队列是否为空。
示例:

MyQueue queue = new MyQueue();

queue.push(1);
queue.push(2);
queue.peek(); // 返回 1
queue.pop(); // 返回 1
queue.empty(); // 返回 false
说明:

你只能使用标准的栈操作 -- 也就是只有 push to top, peek/pop from top, size, 和 is empty 操作是合法的。
你所使用的语言也许不支持栈。你可以使用 list 或者 deque(双端队列)来模拟一个栈,只要是标准的栈操作即可。
假设所有操作都是有效的 (例如,一个空的队列不会调用 pop 或者 peek 操作)。

     public class MyQueue
{
private Stack<int> stack1;
private Stack<int> stack2; /** Initialize your data structure here. */
public MyQueue()
{
stack1 = new Stack<int>();
stack2 = new Stack<int>();
} /** Push element x to the back of queue. */
public void Push(int x)
{
if(stack1.Count > ||(stack1.Count == && stack2.Count == ))
{
stack1.Push(x);
}
else
{
while(stack2.Count > )
{
stack1.Push(stack2.Pop());
} stack1.Push(x);
}
} /** Removes the element from in front of queue and returns that element. */
public int Pop()
{
if (stack1.Count > )
{
while (stack1.Count > )
{
stack2.Push(stack1.Pop());
}
} return stack2.Pop();
} /** Get the front element. */
public int Peek()
{
if (stack1.Count > )
{
while (stack1.Count > )
{
stack2.Push(stack1.Pop());
}
} return stack2.Peek();
} /** Returns whether the queue is empty. */
public bool Empty()
{
return (stack1.Count == && stack2.Count == );
}
}

  上面的做法还行,思路是利用两个栈来进行实现。而想到这个方法时其实是有点小开心的,有点灵机一动的快感,哈哈。队列中的入队操作会将一个元素添加到队列中去,而这个队列会在当前队列中所有元素都出队之后才会被访问到。而栈呢,如果不向栈中添加新的元素,那么下一次出栈操作就会把这个元素给pop出来。因此很容易联想到用两个栈来实现,当需要出队列的时候,我们就把栈中的元素依次pop,并push到另一个栈中,这样最先进入栈中的元素反而就到了栈顶。剩下的就和队列很类似了。

  其实算法的学习中还有很多”类似“的情况,但前提是你要了解两种不同数据结构的特点与作用。优势是什么,劣势是什么。而数据结构与算法也不是孤立的,比如大家都了解的各种排序,如插入排序,冒泡排序,快速排序等等都不是单一孤立使用的。比如各大高级语言的集合类一般都会提供排序方法,作为码农我们直接拿来主义就可以使用了。但其实它们内部是会根据不同的数据量啊,大小等进行不同的处理,调用不同的算法来进行实现的。这些其实也都挺有意思的。

附加一道题目:

  这道题其实感觉有些类似与脑筋急转弯,启发是有时候可能是我们没有按照计算机的方式去思考,反而复杂化了。反正笔者看这道题的解法和欢乐多的网友类似----原来我是个傻子,哈哈。Leetcode第6题:

将一个给定字符串根据给定的行数,以从上往下、从左到右进行 Z 字形排列。

比如输入字符串为 "LEETCODEISHIRING" 行数为 3 时,排列如下:

L C I R
E T O E S I I G
E D H N
之后,你的输出需要从左往右逐行读取,产生出一个新的字符串,比如:"LCIRETOESIIGEDHN"。

请你实现这个将字符串进行指定行数变换的函数:

string convert(string s, int numRows);
示例 1:

输入: s = "LEETCODEISHIRING", numRows = 3
输出: "LCIRETOESIIGEDHN"
示例 2:

输入: s = "LEETCODEISHIRING", numRows = 4
输出: "LDREOEIIECIHNTSG"
解释:

L D R
E O E I I
E C I H N
T S G

public class Solution {
public string Convert(string s, int numRows)
{
if(numRows == )
{
return s;
} var charArray = s.ToCharArray(); string[] resultList = new string[Math.Min(charArray.Length, numRows)]; int currentRow = ;
bool goDown = false; for (int i = ; i < charArray.Length; i++)
{
resultList[currentRow] = resultList[currentRow] + charArray[i]; if (currentRow == || currentRow == numRows - )
{
goDown = !goDown;
} currentRow = goDown ? currentRow + : currentRow - ;
} string result = string.Empty; for (int i = ; i < resultList.Length; i++)
{
result += resultList[i];
} return result;
}
}

  官方的解法传送门在这里, 传送门

  我原本的思路是如何把字符串处理成想要的格式,然后再依次输出。但是看了高手的解答真的很惊喜,何必这样呢,其实我们更简单一些,所见即所得的输出不好嘛,每行看到的是什么就把什么输出就好了,总之感觉十分奇妙。

  

  这两天还看了一些二分法和树的内容,但是还没找些题练练手,晚些再水一篇博客把,嘿嘿。

  另外,希望疫情早点结束,大家的生活回到正规,感谢在一线奋战的医务工作者们。

LeetCode刷题 --杂篇 --数组,链表,栈,队列的更多相关文章

  1. LeetCode刷题总结-数组篇(上)

    数组是算法中最常用的一种数据结构,也是面试中最常考的考点.在LeetCode题库中,标记为数组类型的习题到目前为止,已累计到了202题.然而,这202道习题并不是每道题只标记为数组一个考点,大部分习题 ...

  2. LeetCode刷题总结-数组篇(中)

    本文接着上一篇文章<LeetCode刷题总结-数组篇(上)>,继续讲第二个常考问题:矩阵问题. 矩阵也可以称为二维数组.在LeetCode相关习题中,作者总结发现主要考点有:矩阵元素的遍历 ...

  3. LeetCode刷题总结-数组篇(下)

    本期讲O(n)类型问题,共14题.3道简单题,9道中等题,2道困难题.数组篇共归纳总结了50题,本篇是数组篇的最后一篇.其他三个篇章可参考: LeetCode刷题总结-数组篇(上),子数组问题(共17 ...

  4. LeetCode刷题总结-数组篇(番外)

    本期共7道题,三道简单题,四道中等题. 此部分题目是作者认为有价值去做的一些题,但是其考察的知识点不在前三篇总结系列里面. 例1解法:采用数组索引位置排序的思想. 例2解法:考察了组合数学的组合公式应 ...

  5. leetcode刷题记录——数组与矩阵

    @ 目录 283. 移动零 566. 重塑矩阵 485. 最大连续1的个数 240. 搜索二维矩阵 II 378. 有序矩阵中第K小的元素 645. 错误的集合 287. 寻找重复数 667. 优美的 ...

  6. leetcode 刷题(数组篇)26题 删除有序数组中的重复值 (双指针)

    题目描述 给你一个有序数组 nums ,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度. 不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用 O(1) 额 ...

  7. leetcode 刷题(数组篇)4题 寻找两个正序数组的中位数(二分查找)

    题目描述 给定两个大小分别为 m 和 n 的正序(从小到大)数组 nums1 和 nums2.请你找出并返回这两个正序数组的 中位数 . 示例 1: 输入:nums1 = [1,3], nums2 = ...

  8. leetcode 刷题(数组篇)1题 两数之和(哈希表)

    题目描述 给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 的那 两个 整数,并返回它们的数组下标. 你可以假设每种输入只会对应一个答案.但是,数组中同一个元 ...

  9. leetcode 刷题(数组篇)152题 乘积最大子数组 (动态规划)

    题目描述 给你一个整数数组 nums ,请你找出数组中乘积最大的连续子数组(该子数组中至少包含一个数字),并返回该子数组所对应的乘积. 示例 1: 输入: [2,3,-2,4] 输出: 6 解释: 子 ...

随机推荐

  1. LeetCode 343.整数拆分 - JavaScript

    题目描述:给定一个正整数 n,将其拆分为至少两个正整数的和,并使这些整数的乘积最大化. 返回你可以获得的最大乘积. 题目分析 题目中"n 至少可以拆分为两个正整数的和",这个条件说 ...

  2. 纯JavaScript实现页面行为的录制

    在网上有个开源的rrweb项目,该项目采用TypeScript编写(不了解该语言的可参考之前的<TypeScript躬行记>),分为三大部分:rrweb-snapshot.rrweb和rr ...

  3. 「硬核干货」总结IDEA开发的26个常用设置

    前言 程序员对待IDE都是虔诚的,经常因为谁是最好的IDE而在江湖上掀起波澜,曾经我也是. 后来我遇到了IDEA,从此是它,余生都是它. IDEA 毫无疑问是目前最强大的Java开发工具了,但是大部分 ...

  4. Classmethod and Staticmethod - Python 类方法 和 静态方法

    classmethod and staticmethod classmethod 的是一个参数是类对象 cls (本类,或者子类), 而不是实例对象 instance (普通方法). classmet ...

  5. [redis读书笔记] 第一部分 数据结构与对象 链表

    二 链表 1.链表节点使用ListNode结构,是一个双向的链表,同时,还实现了一个控制所有ListNode的结构list: typedef struct listNode { // 前置节点 str ...

  6. Tomcat 修改日志输出配置 定期删除日志

    tomcat的下的日志catalina.out 和 qc.log疯狂增长,以下是解决办法 我生产环境tomcat版本 Server version: Apache Tomcat/7.0.35 Serv ...

  7. ssh_key认证

    ssh认证流程步骤: 1.主机host_key认证 2.身份验证 3.身份验证通过 原理及更多知识点,请查看好友博客 http://www.cnblogs.com/f-ck-need-u/p/7129 ...

  8. vue路由--静态路由

    vue的单页面应用是基于路由和组件的,路由用于设定访问路径,并将路径和组件映射起来.传统的页面应用,是用一些超链接来实现页面切换和跳转的.在vue-router单页面应用中,则是路径之间的切换,也就是 ...

  9. toj 4353 Estimation(树状数组+二分查找)

    Estimation 时间限制(普通/Java):5000MS/15000MS     运行内存限制:65536KByte总提交: 6            测试通过: 1 描述 “There are ...

  10. leetcode--js--Median of Two Sorted Arrays

     问题描述: There are two sorted arrays nums1 and nums2 of size m and n respectively. Find the median of ...