零基础的我刷力扣一周后,总结了点东西
一、前言
之前一直想学习数据结构与算法,因为一直听说这个很重要嘛,还有力扣这个网站那也是神交已久啊~~
但是又不敢接触,因为恐惧嘛,害怕学不会,害怕被吊打~~~~~
后来遇到了一个大佬,算法大佬,超强的!
————英雄哪里出来
我跟他聊了我的情况,他就推荐我开始刷力扣,刷简单的,通过率高的,先培养习惯,兴趣,信心。然后我就开始了!
小结计划
这是我第一篇小结
以后每周一会做一篇周结
每月月结,同时删除周结
二、相关知识
1. 时间复杂度O()
算法的目的就是为了提高程序的效率,而在优化了程序后,表现最突出的就是程序的运行时间。
那么测试我们的程序是否跑的更快了,难道掐秒计算吗?
举个例子:
程序优化完后,运行一结束。诶诶,快停,记录时间!!看看快了没!
而这个时间,为实际时间,也可以说是绝对时间,但是这个时间能被很多因素影响
而这个因素就有很多了,硬件,软件,系统等…
所以进引入了相对时间的计时方法,也就是时间复杂度,来判断我们的程序是否得到了优化
规定,一段程序的时间由时间复杂度来表示。
而时间复杂度又分为三种,最优情况,最劣情况,平均情况。而这个情况是由问题来决定的
比如:我们将某个正在军训的班级拉出来一排,一排五个人,让他们从左到右依次报数(从1开始)
用这个数来代表他们本来的名字,作为代号
而我们需要找一个叫做张三的人
不过我们不能大声问谁是张三,只能根据代号挨个去问
如果张三的代号为1,那么我们只需要寻找一次就可以
如果为3那么我们需要寻找3次
如果为5或者张三不在这一排,我们就必须查找5次才能得到结果
而这个第一种情况就是最优情况,为O(1),第三种情况为最劣情况,也就是O(n)
通常使用最劣情况来表示一个程序的最终情况,也就是O()
一个简单的赋值语句,判断语句的时间复杂度为O(1),而不管你这个语句有多长,只要他是切实能写出来的次数,都是O(1)
循环语句根据循环的次数的变化而分为O(1),O(N),上面说过O(1)那么O(n)就是循环的次数随着题目或者问题的改变而改变的,就属于O(n)
而判断整个程序时间复杂度的方法为,以时间复杂度最高的为主:也就是说,就算你赋值了1000000个变量,而循环结果是随时间变化的,那么你的程序的时间复杂度为:O(n)
因为随着循环次数的增加,也就是n->无穷大,你的变量数目,也会相对于n来说越来越小。
所以可以忽略不计,为O(1)*O(n)==O(n)
常见的时间复杂度:O(1),O(logn),O(n),O(nlogn),O(n*2),O(2**n)O(n!)
按照从小到大的顺序排列
2. 空间复杂度O()
空间复杂度也具有相同的概念,只是有些地方变得不太一样了
如果说时间还能掐秒计算时间,那么占用空间就没那么好计算了,难不成,你去看看代码多少航,行多的占用内存就大吗?这也不是,有的代码很少,但是需要占用的内存多,有的代码看着很多,但是占用内存很小
空间复杂度是想对占用空间,比如说,你的程序创建100个变量接收了100个数字,字符串,在空间复杂度里面属于O(1),而你创建一个数组,哈希表,栈等就是O(n)
三、刷题小结
自从开始刷力扣,也有些许日子了,从一开始的每日一题,到每日两题,再到学习学到无聊的时候就去刷题,也算是经历了一番蜕变。
从一开始的什么都不懂,做题全靠暴力破解,但现在掌握了几个方法。
也了解了一些关于数据结构与算法的小知识
学习新知识固然重要,但是也需要总结之前的知识,毕竟温故而知新嘛
1. 二分法
二分查找法是一种算法
他经常用在:
给定一个升序的数组/列表和一个目标值,尽可能快的查找其中的目标值
若存在,返回目标值得索引
若不存在,返回-1
这样的场景
相比于直接遍历整个数组,使用二分法无疑会让我们的程序效率更高!
因为是升序的,所以我们可以以数组中间的元素为中线,将数组分为左右两个数组
python代码展示:
target = 7 # 给一个目标值
start = 0 # 用于计算中间值,和后面陆续的将数组划分为两个数组
end = len(li)-1 # 用于计算中间值,记录列表最后值的索引
li = [1, 2, 3, 4, 5, 6 ,7, 8, 9, 10]
while start<end:# 记录一个循环mid = (start+n)//2 # 值为4"""一个升序数组/列表以中间mid(//是保持中间值为整数)为界限看似分成两个数组li_left = [1, 2, 3 ,4, 5]li_right = [6, 7, 8, 9, 10]"""if target>li[mid]:# 如果目标值比中间值大,就说名目标值(7)在右边的列表start = mid+1 # 让start变成右边列表的第一个元素的索引# 抛弃左边的列表不要,只看右边的列表li_right = [6, 7, 8, 9, 10]else:# 如果目标值小于等于中间值,就说明目标值在左边的列表end = mid # 让n变成左边列表的最大值的索引# 抛弃右边的列表不要,只看左边的列表
print("mid的值就是目标值的索引:", mid)
# 运行结果为6
Java代码:
public class Test{public static void main(String[] args){int[] aa = new int[]{1, 2, 3, 4, 5, 6 ,7, 8, 9, 10};int target = 7; // 给一个目标值,查找目标值是否在数组中int start = 0; // 用于计算中间值,和后面陆续的将数组划分为两个数组int mid = 0; // 设置中间值遍历int end = aa.length; // 用于计算中间值,记录列表最后值的索引while(start<end){ // 设置循环条件,当头指针小于尾指针时终止循环mid = (start+end)/2;/*一个升序数组/列表以中间mid(//是保持中间值为整数)为界限看似分成两个数组左边是: [1, 2, 3 ,4, 5]右边是: [6, 7, 8, 9, 10]*/if (target>aa[mid]) start = mid+1; // 如果目标值比中间值大,就说名目标值(7)在右边的列表,让start变成右边列表的第一个元素的索引else end = mid; // 如果目标值小于等于中间值,就说明目标值在左边的列表,让end编程左边列表的尾部}System.out.println("mid的值就是目标值在数组中的索引:"+mid);}
}// 运行结果为6
随着循环的进行,列表会越来越小,最后只剩目标值,然后最小值的索引就是我们需要的值
二分法时间复杂度分析:O(logn) 每次循环使数组长度减半,因此又被称为折半查找法
直接遍历整个数组(暴力解法)时间复杂度分析:O(n)
2. 双指针法
在我们的二分法中就是用了双指针的方法,起始时一个指针指向数组的头部,一个指针指向数组的尾部,使用这种方法会让我们对数组的操作更加流畅一些。
双指针法常常是用在:
查找某些元素时
力扣的第一道题就是一个经典的双指针优化程序的题目
给你一个目标值和一个有序数组
找出数组中和为目标值的元素
返回她们的下标
元素不能与自己相加
正常的做法是进行嵌套循环,挨个查找,这样的时间复杂度为:O(n*2)
而如果使用双指针的方法,结合二分法就能使时间复杂度降低到:O(logn)
遍历的方法就相当于一个人在找东西,双指针的方法就好像是两个人在找东西
打个例子:
我有一块种着10棵树的地
有人告诉我,你有一棵树需要浇水了
如果只有我自己(正常遍历)
并且我不需要跑到树前面观察才能判断我的树是否需要浇水
我只能一棵一棵的找,然后判断
而如果我有一个助手(双指针)
我就可以缩短排查的时间
java:
public class Shuzu {public static void main(String[] args) {int target = 7;int[] arr = new int[]{1, 2, 3, 4, 5, 6, 7, 8, 9};System.out.println(ArrD(7,arr)+"\n"+ArrS(target,arr));}static int ArrD(int target, int[] arr) {// 单指针for (int i = 0; i < arr.length; i++) {if (arr[i] == target) return i;}return -1;}static int ArrS(int target, int[] arr){// 双指针int end = arr.length-1;int start = 0;while (start<end){if (arr[start]==target) return start;if (arr[end]==target) return end;start++;end--;}return -1;}
}
py:
def ArrD(target, arr):# 单指针for i in range(len(arr)):if arr[i]target: return ireturn -1;
def ArrS(target, arr):# 双指针start = 0end = len(arr)-1while start<end:if arr[start]==target: return startif arr[end]==target: return endstart+=1end-=1return endtarget = 7
arr = [1, 2, 3, 4, 5, 6, 7, 8, 9]
print(ArrD(target, arr), "\n", ArrS(target, arr))
3. 递归
递归与其说是一种算法,不如说是一种思想。
它更类似于我们高中数学学过的数列的递推推导式:A(n) = A(n-1)+5 首项为1
让你通过这个式子计算第n项的值的话
你高中会使用它推导出一个通项公式,再将n代入求解
但是再计算机眼里就不用这么麻烦
你只需要每次调用这个公式,然后计算出值就好
在编程语言里就是 :定义一个函数,调用自身,返回结果就是递归
就相当于计算机帮你从1开始执行了很多遍的A(n) = A(n-1)+5
无限套娃?不不不,他还是有个限度的,没法无限,哈哈哈
比如需要求A(5),那么就是:
A(5) = A(4)+5
A(4) = A(3)+5
A(3) = A(2)+5
A(2) = A(1)+5
A(1) = 3
A(5) = 3+5+5+5+5=23
代码实现:
java代码:
public class Digui {public static void main(String[] args) {int sum = Shu(5);System.out.println(sum);}static int Shu(int n){if (n<=1) return 3;else return Shu(n-1)+5;}
}
py代码:
def Shu(n:int)->int:if n<=1: return 3else: return Shu(n-1)+5print(Shu(5))
最后的计算结果是23
4. 数组
什么是数组?数组就是存储多个相同数据的集合,他们的内存地址是相邻的,所以可以通过数组取值。
这么说,是不是有点不好理解,那么这样呢?
我有一颗白菜,手拿着就能回家,那如果是十几颗呢?
我就可以用麻袋!麻袋!装进去,带回家!是的你要存的数据就是白菜,而这个数组就是你要用的麻袋~~~~~
麻袋中的白菜怎么拿出来我需要用的呢?
下标,数组中的下标是以0开始的,什么是下标,就是你从0开始查,查到某个你要的数据,查到几,下标就是几,就相当于,我在装白菜的时候,说“这是第0个白菜,这是第1个白菜…”,而他们也能听懂(别管他们能不能听懂,我说能就能,哈哈~~),等我需要哪一颗白菜的时候,喊一声,他就自己跳出来了
当然我们的数组一般存储的数据比较多,而计算机又不和人一样能够直接看到数组的全部元素,他只记得里面第一颗白菜的样子,所以我们在查找某个元素,但是又不知道他在哪里的时候,只能通过遍历的手段来获取了
遍历每一棵白菜,将他与我们需要找的白菜对比没如果是就不找了,如果不是就继续找。
具体的代码形式我就不多说了,这个都是知道的。
5. 字符串
字符串是我们在编程语言里面见到的第一个数据结构 hello world
当然,字符串不仅是我们滴各一人士的数据结构,也是我们在生活中用到最多的,比如我们网上聊天,就是字符串,看的小说,是字符串…
而有的字符擦混存储在文件中供计算机读取,然后输出到屏幕上给我们看。
字符串可以看成是一个字符型数组,但是又不尽相同
字符串可以遍历,查询,拼接,但是不能修改
有的时候拼接用得好也能很大程度上降低我们解决问题的难度
我们可以通过运算符号对字符串进行
运算符 | 作用 | 实例 |
---|---|---|
+ | 拼接字符串 | “a”+“a”=>“aa” |
= | 赋值字符串 | “a”=“b”=>“b” |
== | 判断字符串是否相等 | “a”==“b”=>false |
[] | 通过下标获取字符串中的字符 | “asd”[0]=>“a” |
说起字符串,能说的也可以很多,也可以很少
说多了有AI的NLP自然语言处理,K近邻算法,正则表达式…
这里就不多说了,先学会基本操作
6. 链表
链表是一种抽象的数据结构,他实际上是一个链表对象,头结点就是这个链表对象,而链表的没一个节点都是一个对象。
链表是一个不定长的线性表数据结构,链表没有内置方法来获取其长度,只能通过遍历来获得里面的内容。
链表实现:
java:
class ListNode{public int val; // 存储的值public ListNode next; // 指向下一节点public ListNode(int val){ // 构造函数/方法this.val = val;next = null;}
}
py:
class ListNode:def __init__(self,val): # 构造函数self.val = val # 存储的值next = None # 指向下一节点
是的,链表就是这样实现的。我们一般只能拿到头结点,然后通过判断下一节点是否为空位约束条件来终止循环。
实例:
给你个链表[1, 2, 3, 4, 5]
求链表的长度
java代码:
package com.example.demo;public class ListNodeStudy {public static void main(String[] args) {ListNode h1 = new ListNode(1); // 1ListNode h2 = new ListNode(2); // 2ListNode h3 = new ListNode(3); // 3ListNode h4 = new ListNode(4); // 4ListNode h5 = new ListNode(5); // 5h1.next = h2; // 下一节点h2.next = h3; // 下一节点h3.next = h4; // 下一节点h4.next = h5; // 下一节点// 题目的链表是这样是实现的,不过不会让你去实现,而是给你h1让你来找长度System.out.println(len(h1));}static int len(ListNode head){int len = 0; // 为链表长度定义变量while (head!=null){ // 遍历链表获取长度len++;head = head.next;}return len;}
}
class ListNode{public int val; // 存储的值public ListNode next; // 指向下一节点public ListNode(int val){ // 构造函数/方法this.val = val;next = null;}
}
py:
class ListNode:def __init__(self, val): # 构造函数self.val = val # 存储的值self.next = None # 指向下一节点h1 = ListNode(1)
h2 = ListNode(2)
h3 = ListNode(3)
h4 = ListNode(4)
h5 = ListNode(5)
h1.next = h2
h2.next = h3
h3.next = h4
h4.next = h5def ListNodeLen(head: ListNode) -> int:len = 0while head != None:len += 1head = head.nextreturn lenprint(ListNodeLen(h1))
三、结语
也许我学的慢,但是我始终都在进步!那我总有一天会成功。
零基础的我刷力扣一周后,总结了点东西相关推荐
- 【关于为什么要刷力扣的思考】记第二次周赛AK
前言 从上次AK周赛的一月底,磕磕绊绊到五月初,总共经历了20多场的周赛 在这20场周赛中,四题:三题:两题:一题 = 2:12:8:1 总体来说应该还是在两到三题中间徘徊 但很多时候做出的两题,并非 ...
- VS Code刷力扣LeetCode方法
VS Code刷力扣LeetCode方法 一.LeetCode扩展安装 二.Node.js安装 三.账号登录 3.1 选择 力扣中国版 3.2 选择 Cookies方式登录 3.3 Cookies获取 ...
- 在 vscode 上刷力扣 Leetcode 可以这样来
背景 神奇的算法网站 LeetCode 值得驻留,网页版似乎不太方便,作为习惯于在编译器上敲代码的你,如何 vscode 上优雅的刷力扣 Leetcode,在本地配置,记录下来方便备查. 环境前置:电 ...
- 程序员面试需要刷力扣算法题吗
这里写目录标题 1. 程序员面试需要刷力扣算法题吗 1.1. 算法题的一些特征 1.2. 为什么要考查算法 1.3. 目前面试主要考查 3 类 1. 程序员面试需要刷力扣算法题吗 1.1. 算法题的一 ...
- 零基础html学习/刷题-第一期
之前写的html学习的文章都是零零散散的,这次出个整合的专栏,把内容集中起来,做个知识复盘,顺带刷刷题.牛客网非常值得一用,刷题也很好刷!对于基础入门最合适不过. 博主主页:WDm-xmax 原id: ...
- 20201219:力扣219周周赛题解
力扣219周周赛题解 题目 思路与算法 代码实现 复杂度分析 题目 比赛中的配对次数 十-二进制数的最少数目 石子游戏 VII 堆叠长方体的最大高度 思路与算法 比赛中的配对次数 两两比赛,淘汰剩一支 ...
- 20201007:力扣209周周赛题解记录(上)
力扣209周周赛题解记录(上) 题目 思路与算法 代码实现 复杂度分析 题目 特殊数组的特征值 奇偶树 思路与算法 第一题单纯的暴力就行,应该是可以用二分之类的改善复杂度,没必要赘述,直接上暴力遍历, ...
- 20200616:力扣193周周赛上
力扣193周周赛上 题目 思路与算法 代码实现 写在最后 题目 一维数组的动态和 不同整数的最少数目 思路与算法 第一题没啥好说的,动态和,dp最基础的东西. 第二题主要是一个贪心的过程,既然要剩下的 ...
- 20200505:力扣151周周赛上
力扣151周周赛上 题目 思路与算法 代码实现 题目 查询无效交易 2.比较字符串最小字母出现频次 思路与算法 第一题直接将我们需要的这四组数据包装成一个Transaction对象,主要是注意书写问题 ...
最新文章
- 获取当前脚本目录路径问题汇总
- 理解Linux和其他UNIX-Like系统上的平均负载
- java 内存_java节省内存的几条建议
- Q1全球智能机销量增长3.9% 三星苹果华为居三甲
- 全文索引 排名计算问题
- 聊聊高并发(三十三)Java内存模型那些事(一)从一致性(Consistency)的角度理解Java内存模型
- 常用命令-tar 加密
- php mysql 排名算法_MySQL PHP:优化排名查询和计数子查询
- php 支付加密,关于支付时rsa加密解密的函数
- Juqery Html(),append()等方法的Bug
- SQL Server 不同数据库导入指定数据解决方案
- 想买基金,在哪个银行开户好呢?
- 组织健康的路径:良性互动
- layui select change事件_一道2020年全国生物学联赛试题背后的“眼齿鸟事件”
- NYOJ 93 汉诺塔(三) 【栈的简单应用】
- win10连接共享打印机_win7共享出来的打印机部分电脑无法连接的问题
- Kali安装AWVS
- python网络测速_网络测速命令--speedtest
- PLC、PAC、PC-Based、软PLC傻傻分不清
- python从图片提取文字_用python提取图片文字