元旦匆匆而过,2020年的春节又接踵而来,你们除了忙的提着裤子加班、年末冲冲冲外,还有着对于明年的迷茫和期待!2019年有多少苦涩心酸,2020年就有更多幸福美好,加油,奥利给!怀着一颗积极向上的心,来面对将来每一天的挑战!javascript
所谓“兵马未动,粮草先行”,咱们打响明天的战役也须要精神食粮来作后勤保障才是。在此我整理了多位从业者和我在2019年末至2020年初的一厂面试精选题,但愿对磨砺锋芒、奋发向上的小伙伴有所帮助,祝你早日剑指大厂,扬帆起航,奥利给!css
有跨站脚本攻击(XSS)、跨站请求伪造(CSRF)、点击劫持、SQL注入、DDOS攻击、DNS劫持html
永远不要信任用户的输入。对用户的输入进行校验,能够经过正则表达式,或限制长度;对单引号和双"-"进行转换等。前端
永远不要使用动态拼装sql,可使用参数化的sql或者直接使用存储过程进行数据查询存取。java
永远不要使用管理员权限的数据库链接,为每一个应用使用单独的权限有限的数据库链接。node
不要把机密信息直接存放,加密或者hash掉密码和敏感的信息。webpack
应用的异常信息应该给出尽量少的提示,最好使用自定义的错误信息对原始错误信息进行包装ios
sql注入的检测方法通常采起辅助软件或网站平台来检测,软件通常采用sql注入检测工具jsky,网站平台就有亿思网站安全平台检测工具。git
xss:跨站点攻击。xss攻击的主要目的是想办法获取目标攻击网站的cookie,由于有了cookie至关于有了session,有了这些信息就能够在任意能接进互联网的PC登录该网站,并以其余人的身份登录作破坏。预防措施防止下发界面显示html标签,把</>等符号转义。web
csrf:跨站点假装请求。csrf攻击的主要目的是让用户在不知情的状况下攻击本身已登陆的一个系统,相似于钓鱼。如用户当前已经登录了邮箱或bbs,同时用户又在使用另一个,已经被你控制的网站,咱们姑且叫它钓鱼网站。这个网站上面可能由于某个图片吸引你,你去点击一下,此时可能就会触发一个js的点击事件,构造一个bbs发帖的请求,去往你的bbs发帖,因为当前你的浏览器状态已是登录状态,因此session登录cookie信息都会跟正常的请求同样,纯自然的利用当前的登录状态,让用户在不知情的状况下,帮你发帖或干其余事情。预防措施,请求加入随机数,让钓鱼网站没法正常伪造请求。
DNS劫持 DNS劫持就是经过劫持了DNS服务器,经过某些手段取得某域名的解析记录控制权,进而修改此域名的解析结果,致使对该域名的访问由原IP地址转入到修改后的指定IP。DNS劫持经过篡改DNS服务器上的数据返回给用户一个错误的查询结果来实现的。
DNS污染 DNS污染,指的是用户访问一个地址,国内的服务器(非DNS)监控到用户访问的已经被标记地址时,服务器假装成DNS服务器向用户发回错误的地址的行为。范例,访问Youtube、Facebook之类网站等出现的情况。
1.DNS解析
2.发送tcp链接
3.发送http请求
4.服务器处理请求并返回http报文
5.浏览器解析渲染界面
6.链接结束
参考地址:http://www.javashuo.com/article/p-kftntixa-my.html
咱们一般认为浏览器开始渲染 标签或者解析完
标签的时刻就是页面白屏结束的时间点。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>白屏</title> <script type="text/javascript"> // 不兼容performance.timing 的浏览器,如IE8 window.pageStartTime = Date.now(); </script> <!-- 页面 CSS 资源 --> <link rel="stylesheet" href="common.css"> <link rel="stylesheet" href="page.css"> <script type="text/javascript"> // 白屏时间结束点 window.firstPaint = Date.now(); </script> </head> <body> <!-- 页面内容 --> </body> </html>
所以白屏时间则能够这样计算出:
可以使用Performance API时
白屏时间 = firstPaint - performance.timing.navigationStart;
不可以使用Performance API时
白屏时间 = firstPaint - pageStartTime
参考地址: https://segmentfault.com/p/1210000011237223/read
什么是xss攻击:
攻击者经过篡改网页,嵌入恶意js代码,当用户访问网页时,被嵌入的js代码会被执行,从而达到恶意攻击用户的一种方式;
如何防范 XSS 攻击:
一、对输入的字符串作长度限制;
二、对用户的输入进行过滤,如对& < > " ' /等进行转义;
三、获取用户的输入,不用innerHtml,用innerText.
CSRF攻击的原理:
跨站请求伪造,攻击者构造某个网站后台接口的请求地址,诱导用户去点击或者用特殊的方法让 该请求地址自动加载,用户在登录的状况下,这个请求被服务器端接收后误觉得是用户合法的操做,
对于get形式的接口跨域轻易被攻击,对于psot形式的接口也不是100%安全,攻击者可诱导用户带from表单可用post形式提交参数的页面。
如何防范CSRF攻击:
一、验证 HTTP Referer 字段;
二、在请求地址中添加 token 并验证;
三、在 HTTP 头中自定义属性并验证。
合理的title、description、keywords:搜索对着三项的权重逐个减少,title值强调重点便可,重要关键词出现不要超过2次,并且要靠前,不一样页面title要有所不一样;description把页面内容高度归纳,长度合适,不可过度堆砌关键词,不一样页面description有所不一样;keywords列举出重要关键词便可
语义化的HTML代码,符合W3C规范:语义化代码让搜索引擎容易理解网页
重要内容HTML代码放在最前:搜索引擎抓取HTML顺序是从上到下,有的搜索引擎对抓取长度有限制,保证重要内容必定会被抓取
重要内容不要用js输出:爬虫不会执行js获取内容
少用iframe:搜索引擎不会抓取iframe中的内容
非装饰性图片必须加alt
提升网站速度:网站速度是搜索引擎排序的一个重要指标
Hybrid App主要以JS+Native二者相互调用为主,从开发层面实现“一次开发,多处运行”的机制,成为真正适合跨平台的开发。Hybrid App兼具了Native App良好用户体验的优点,也兼具了Web App使用HTML5跨平台开发低成本的优点。
目前已经有众多Hybrid App开发成功应用,好比美团、爱奇艺、微信等知名移动应用,都是采用Hybrid App开发模式。
移动应用开发的方式,目前主要有三种:
Native App: 本地应用程序(原生App),通常依托于操做系统,有很强的交互,是一个完整的App,可拓展性强,须要用户下载安装使用。(简单来讲,原生应用是特别为某种操做系统开发的,好比iOS、Android、黑莓等等,它们是在各自的移动设备上运行的)
该模式一般是由“云服务器数据+APP应用客户端”两部份构成,APP应用全部的UI元素、数据内容、逻辑框架均安装在手机终端上。
原生应用程序是某一个移动平台(好比iOS或安卓)所特有的,使用相应平台支持的开发工具和语言(好比iOS平台支持Xcode和Objective-C,安卓平台支持Eclipse和Java)。原生应用程序看起来(外观)和运行起来(性能)是最佳的。
Web App:网页应用程序(移动web)指采用Html5语言写出的App,不须要下载安装。相似于如今所说的轻应用。生存在浏览器中的应用,基本上能够说是触屏版的网页应用。(Web应用本质上是为移动浏览器设计的基于Web的应用,它们是用普通Web开发语言开发的,能够在各类智能手机浏览器上运行)
Web App开发便是一种框架型APP开发模式(HTML5 APP 框架开发模式),该开发具备跨平台的优点,该模式一般由“HTML5云网站+APP应用客户端”两部份构成,APP应用客户端只需安装应用的框架部份,而应用的数据则是每次打开APP的时候,去云端取数据呈现给手机用户。
HTML5应用程序使用标准的Web技术,一般是HTML五、JavaScript和CSS。这种只编写一次、可处处运行的移动开发方法构建的跨平台移动应用程序能够在多个设备上运行。虽然开发人员单单使用HTML5和JavaScript就能构建功能复杂的应用程序,但仍然存在一些重大的局限性,具体包括会话管理、安全离线存储以及访问原生设备功能(摄像头、日历和地理位置等)。
Hybrid App:混合应用程序(混合App)指的是半原生半Web的混合类App。须要下载安装,看上去相似Native App,但只有不多的UI Web View,访问的内容是 Web 。
混合应用程序让开发人员能够把HTML5应用程序嵌入到一个细薄的原生容器里面,集原生应用程序和HTML5应用程序的优势(及缺点)于一体。
混合应用你们都知道是原生应用和Web应用的结合体,采用了原生应用的一部分、Web应用的一部分,因此必须在部分在设备上运行、部分在Web上运行。不过混合应用中比例很自由,好比Web 占90%,原生占10%;或者各占50%。
一、meta:viewport 防止浏览器自动缩放
<meta name="viewport" content="width=device-width , user-scalable=no , initial-scale=1.0 , maximum-scale=1.0 , minimum-scale=1.0">
二、响应式布局(responsive)
响应式布局可以使网站在不一样的设备上浏览时对应不一样分辨率皆有适合的呈现
其布局经过媒体查询@media实现,
新闻及门户网站能够用响应式布局,但大型网站媒体查询有其局限性
实际上除了响应式,网站一般会采用:1.提供两套html由后端根据用户设备来切换 2.提供两个彻底不一样的url由后端根据用户设备来跳转
三、经过动态rem实现
css常见的单位有: px,em,rem ,vh ,vw
font-size
同样须要注意:
<script> document.write(` <style>{html{font-size:${window.innerWidth}px}}</style>`) </script>
参考地址:https://www.jianshu.com/p/c6d82db7ad62
Git回滚代码到某个commit
回退命令:
git reset --hard HEAD^ 回退到上个版本
git reset --hard HEAD~3 回退到前3次提交以前,以此类推,回退到n次提交以前
git reset --hard commit_id 退到/进到,指定commit的哈希码(此次提交以前或以后的提交都会回滚)
参考地址 :https://www.jianshu.com/p/57f0626a1432
设计模式的定义:在面向对象软件设计过程当中针对特定问题的简洁而优雅的解决方案
class CreateUser { constructor(name) { this.name = name; this.getName(); } getName() { return this.name; } } // 代理实现单例模式 var ProxyMode = (function() { var instance = null; return function(name) { if(!instance) { instance = new CreateUser(name); } return instance; } })(); // 测试单体模式的实例 var a = new ProxyMode("aaa"); var b = new ProxyMode("bbb"); // 由于单体模式是只实例化一次,因此下面的实例是相等的 console.log(a === b); //true
/*策略类*/ var levelOBJ = { "A": function(money) { return money * 4; }, "B" : function(money) { return money * 3; }, "C" : function(money) { return money * 2; } }; /*环境类*/ var calculateBouns =function(level,money) { return levelOBJ[level](money); }; console.log(calculateBouns('A',10000)); // 40000
var imgFunc = (function() { var imgNode = document.createElement('img'); document.body.appendChild(imgNode); return { setSrc: function(src) { imgNode.src = src; } } })(); var proxyImage = (function() { var img = new Image(); img.onload = function() { imgFunc.setSrc(this.src); } return { setSrc: function(src) { imgFunc.setSrc('./loading,gif'); img.src = src; } } })(); proxyImage.setSrc('./pic.png');
LRU(Least recently used,最近最少使用)算法根据数据的历史访问记录来进行淘汰数据,其核心思想是“若是数据最近被访问过,那么未来被访问的概率也更高”。
参考: http://www.javashuo.com/article/p-aanjkckp-dn.html
给定一个长度为N的数组,找出一个最长的单调递增子序列,子序列不必定连续,但初始顺序不能乱。
例如:给定一个长度为6的数组A{4, 5, 7, 1,3, 9},则其最长的单调递增子序列为{4,5,7,9},长度为4。
//找出最长子序列的长度
int LargestListFind() { int vec[6] = {4,5,7,1,3,9}; int d[6] = {1}; for(unsigned int i = 0; i < 6; i++) { d[i] = 1; for(unsigned int j = 0; j < i; j++) { if(vec[j] < vec[i] && d[j] >= d[i]) d[i] = d[j] + 1; } } int Max = -1; for(unsigned int i = 0; i < 6; i++) if(Max < d[i]) Max = d[i]; return Max; }
参考 : http://www.javashuo.com/article/p-eljxsfxc-dx.html
咱们先来整理一下什么是平衡二叉树?
知足如下两点的就是平衡二叉树:
1.左右子树的高度差不能超过1
2.左右子树也是平衡二叉树
int IsBalance(BNode *root,int *pHeight) { if (root == NULL) { *pHeight = 0; return 1; } int leftHeight; int rightHeight; int leftBalance = IsBalance(root->left, &leftHeight); int rightBalance = IsBalance(root->right, &leftHeight); *pHeight = MAX(leftHeight, rightHeight) + 1; if (leftBalance == 0 || rightBalance == 0) { return 0; } int diff = leftHeight - rightHeight; if (diff < -1 || diff>1) { return 0; } else { return 1; } }
参考 :https://blog.csdn.net/WYH19951220/article/details/88891672
示例:
给定 “abcabcbb” ,没有重复字符的最长子串是 “abc” ,那么长度就是3。
给定 “bbbbb” ,最长的子串就是 “b” ,长度是1。
给定 “pwwkew” ,最长子串是 “wke” ,长度是3。请注意答案必须是一个子串,“pwke” 是 子序列 而不是子串。
public int LengthOfLongestSubstring(string str) { int resLength = 0; int strLength = str.Length; int i = 0, j = 0; HashSet<string> hashSet = new HashSet<string>(); while (i < strLength && j < strLength) { string oneStrJ = str.Substring(j,1); if (!hashSet.Contains(oneStrJ)) { hashSet.Add(oneStrJ); j++; resLength = Math.Max(resLength,j-i); } else { string oneStrI = str.Substring(i, 1); hashSet.Remove(oneStrI); i++; } } return resLength; }
参考:https://blog.csdn.net/xc121566/article/details/80827129
判断是否存在一条直线,让全部线段在直线上的投影存在一个公共点。这个问题能够转化为这样的问题:
是否存在一条直线能够穿过全部线段,进而转化成通过某两个线段端点的直线可否穿过全部线段。(具体证实能够自行百度)
如今问题简化了,只须要枚举两个端点(包括同一条线段的)判断是否相交就好了。
坑:枚举的两个端点可能重合
#include <cstdio> #include <iostream> #include <cmath> const double eps=1e-8; using namespace std; struct Point { double x, y; Point(double x=0, double y=0) : x(x),y(y) {} }; int n,T; Point p[1005][2]; typedef Point Vector; Vector operator + (Vector A,Vector B) {return Vector(A.x+B.x,A.y+B.y);} Vector operator - (Vector A,Vector B) {return Vector(A.x-B.x,A.y-B.y);} Vector operator * (Vector A,double p) {return Vector(A.x*p,A.y*p);} Vector operator / (Vector A,double p) {return Vector(A.x/p,A.y/p);} bool operator < (const Point& a,const Point& b) { return a.x < b.x || (a.x == b.x && a.y < b.y); } int dcmp(double x) { if (fabs(x) < eps) return 0; else return x<0?-1:1; } bool operator == (const Point &a,const Point &b) { return dcmp(a.x-b.x) == 0 && dcmp(a.y-b.y) == 0; } double Cross(Vector A,Vector B) { return A.x*B.y - A.y*B.x; } // 判断直线与线段是否相交 bool SegLineInt(Point a1,Point a2,Point b1,Point b2) { double c1 = Cross(a2-a1,b1-a1), c2 = Cross(a2-a1,b2-a1); return dcmp(c1)*dcmp(c2)<=0; } // 判断一条直线是否知足条件 bool judge(Point A,Point B) { // 一个坑,选择的两个点不能重合 if (A==B) return false; for (int i=1;i<=n;i++) if (!SegLineInt(A,B,p[i][0],p[i][1])) return false; return true; } int main() { cin >> T; while(T--) { cin >> n; for (int i=1;i<=n;i++) scanf("%lf%lf%lf%lf",&p[i][0].x,&p[i][0].y,&p[i][1].x,&p[i][1].y); if (n==1) {printf("Yes!\n"); continue;} bool flag=0; // 枚举两个端点 for (int i=1;i<=n&&!flag;i++) { for (int j=i+1;j<=n;j++) { flag|=judge(p[i][0],p[j][0]); flag|=judge(p[i][0],p[j][1]); flag|=judge(p[i][1],p[j][0]); flag|=judge(p[i][1],p[j][1]); if (flag) break; } } if (flag) printf("Yes!\n"); else printf("No!\n"); } return 0; }
参考:https://blog.csdn.net/radium_1209/article/details/89520666
参考:https://blog.csdn.net/baidu_38621657/article/details/88369398
参考:https://blog.csdn.net/ValDC_Morning/article/details/76615752
http://www.javashuo.com/article/p-fwemjzqu-my.html
插入排序算法是基于某序列已经有序排列的状况下,经过一次插入一个元素的方式按照原有排序方式增长元素。这种比较是从该有序序列的最末端开始执行,即要插入序列中的元素最早和有序序列中最大的元素比较,若其大于该最大元素,则可直接插入最大元素的后面便可,不然再向前一位比较查找直至找到应该插入的位置为止。插入排序的基本思想是,每次将1个待排序的记录按其关键字大小插入到前面已经排好序的子序列中,寻找最适当的位置,直至所有记录插入完毕。执行过程当中,若遇到和插入元素相等的位置,则将要插人的元素放在该相等元素的后面,所以插入该元素后并未改变原序列的先后顺序。咱们认为插入排序也是一种稳定的排序方法。插入排序分直接插入排序、折半插入排序和希尔排序3类。
冒泡排序算法是把较小的元素往前调或者把较大的元素日后调。这种方法主要是经过对相邻两个元素进行大小的比较,根据比较结果和算法规则对该二元素的位置进行交换,这样逐个依次进行比较和交换,就能达到排序目的。冒泡排序的基本思想是,首先将第1个和第2个记录的关键字比较大小,若是是逆序的,就将这两个记录进行交换,再对第2个和第3个记录的关键字进行比较,依次类推,重复进行上述计算,直至完成第(n一1)个和第n个记录的关键字之间的比较,此后,再按照上述过程进行第2次、第3次排序,直至整个序列有序为止。排序过程当中要特别注意的是,当相邻两个元素大小一致时,这一步操做就不须要交换位置,所以也说明冒泡排序是一种严格的稳定排序算法,它不改变序列中相同元素之间的相对位置关系。
选择排序算法的基本思路是为每个位置选择当前最小的元素。选择排序的基本思想是,基于直接选择排序和堆排序这两种基本的简单排序方法。首先从第1个位置开始对所有元素进行选择,选出所有元素中最小的给该位置,再对第2个位置进行选择,在剩余元素中选择最小的给该位置便可;以此类推,重复进行“最小元素”的选择,直至完成第(n-1)个位置的元素选择,则第n个位置就只剩惟一的最大元素,此时不需再进行选择。使用这种排序时,要注意其中一个不一样于冒泡法的细节。举例说明:序列58539.咱们知道第一遍选择第1个元素“5”会和元素“3”交换,那么原序列中的两个相同元素“5”之间的先后相对顺序就发生了改变。所以,咱们说选择排序不是稳定的排序算法,它在计算过程当中会破坏稳定性。
快速排序的基本思想是:经过一趟排序算法把所须要排序的序列的元素分割成两大块,其中,一部分的元素都要小于或等于另一部分的序列元素,而后仍根据该种方法对划分后的这两块序列的元素分别再次实行快速排序算法,排序实现的整个过程能够是递归的来进行调用,最终可以实现将所需排序的无序序列元素变为一个有序的序列。
归并排序算法就是把序列递归划分红为一个个短序列,以其中只有1个元素的直接序列或者只有2个元素的序列做为短序列的递归出口,再将所有有序的短序列按照必定的规则进行排序为长序列。归并排序融合了分治策略,即将含有n个记录的初始序列中的每一个记录均视为长度为1的子序列,再将这n个子序列两两合并获得n/2个长度为2(当凡为奇数时会出现长度为l的状况)的有序子序列;将上述步骤重复操做,直至获得1个长度为n的有序长序列。须要注意的是,在进行元素比较和交换时,若两个元素大小相等则没必要刻意交换位置,所以该算法不会破坏序列的稳定性,即归并排序也是稳定的排序算法。
参考: http://www.javashuo.com/article/p-xkqvkpca-gt.html
写一个程序建立一棵二叉树,并按照必定规则,输出二叉树根节点到叶子节点的路径。
规则以下:
一、从最顶端的根结点,到最下面的叶子节点,计算路径经过的全部节点的和,若是与设置的某一值的相同,那么输出这条路径上的全部节点。
二、从根节点遍历树时,请请按照左到右遍历,即优先访问左子树的节点。
二叉树建立规则:从上到下一层一层的,按照从左到右的顺序进行构造
import java.util.Scanner; public class Main { public static int counter = 0; public static void main(String[] args) { Scanner sc = new Scanner(System.in); int N = Integer.valueOf(sc.nextLine()); String line = sc.nextLine(); compute(N, line); } public static void compute(int N, String line){ String[] arr = line.split(","); int len = arr.length; //从index=1开始存数据 Node[] nodeArr = new Node[len + 1]; for(int i = 0; i < len; i++){ int val = Integer.valueOf(arr[i]); nodeArr[i + 1] = new Node(val); } //构建二叉树 Node root = nodeArr[1]; for(int i = 1; i < len + 1; i++){ if(i * 2 < len + 1){ nodeArr[i].left = nodeArr[2 * i]; } if(i * 2 + 1 < len + 1){ nodeArr[i].right = nodeArr[2 * i + 1]; } } // printTree(root); printPaths(root, len, N); } public static void printTree(Node root){ if(root == null){ return; } System.out.println(root.val); if(root.left != null){ printTree(root.left); } if(root.right != null){ printTree(root.right); } } public static void printPaths(Node root, int n, int N) { int[] path = new int[n]; printPaths(root, path, 0, N); if(counter == 0){ System.out.println("error"); } } public static void printPaths(Node root, int[] path, int pathLen, int N) { if (root == null) return; path[pathLen++] = root.val; if (root.left == null && root.right == null) { printArray(path, pathLen, N); } else { printPaths(root.left, path, pathLen, N); printPaths(root.right, path, pathLen, N); } } public static void printArray(int[] ints, int len, int N) { int total = 0; StringBuilder sb = new StringBuilder(); for (int i = 0; i < len; i++) { sb.append(ints[i] + ","); total += ints[i]; } if(total == N){ System.out.println(sb.toString().substring(0, sb.toString().length() - 1)); counter++; } } } class Node{ public int val; public Node left; public Node right; public Node(int val){ this.val = val; } }
给定一个链表,要求每隔k个元素反转 即链表为1->2->3->4->5->6->7->8
当k=2时,链表为2->1->4->3->6->5->8->7
当k=5时,链表5->4->3->2->1->6->7->8
class Node<T> { public T data; public Node<T> next; Node(T dataPortion) { data = dataPortion; next = null; } Node(T dataPortion, Node<T> nextNode) { data = dataPortion; next = nextNode; } } public class ListKReverse { public static void main(String[] args) { ListKReverse s = new ListKReverse(); Node n1 = new Node(1); Node n2 = new Node(2); Node n3 = new Node(3); Node n4 = new Node(4); Node n5 = new Node(5); Node n6 = new Node(6); Node n7 = new Node(7); Node n8 = new Node(8); n1.next = n2; n2.next = n3; n3.next = n4; n4.next = n5; n5.next = n6; n6.next = n7; n7.next = n8; Node head = s.ReverseInGroups(n1, 4); while (head != null) { System.out.print(head.data+" "); head = head.next; } System.out.println(); } public Node ReverseInGroups(Node current, int k) { if (current == null || current.next == null ) return current; int n=0; Node oldHead=current; while(current!=null) { current=current.next; n++; } System.out.println(n); int reverseNum=n/k; current=oldHead; Node newHead = current; Node previousGroupTail = null; int count = 1; int num=0; while (current != null&&num<reverseNum) { Node groupTail = current; Node prev = null; Node next = null; for (int i = 1; i <= k && current != null; i++) { next = current.next; current.next = prev; prev = current; current = next; } if (count == 1) { newHead = prev; count++; } if (previousGroupTail != null) { previousGroupTail.next = prev; } previousGroupTail = groupTail; num++; } if(current!=null) if (previousGroupTail != null) previousGroupTail.next = current; return newHead; } }
递归算法:
f(0) = 0 f(1) = 1 f(2) = 2 其次,当n=3时,青蛙的到达第三阶的前第位置有两种状况,阶一,阶二,因此递推f(3)=f(2)+f(1).即n>=3时,f(n)=f(n-1)+f(n-2)。
long facinabo(int n) { if(n==0) { return 0; } if(n==1) { return 1; } if(n==2) { return 2; } else { return facinabo(n-1)+facinabo(n-2); } }
复杂度:O(n*n)。
非递归算法
long facinabo(int n) { int sum=0; int q1=1; int q2=2; if(n==0) { return 0; } if(n==1) { return 1; } if(n==2) { return 2; } for(int i=3;i<=n;i++){ sum = q1+q2; q1=q2; q2=sum; } return sum; }
时间复杂度:O(n)。
var ans,res,len; var dfs=function(index,sum,candidates,target){ if(sum===target){ var tmp=res.map(function(item){ return item; }) ans.push(tmp); // console.log(res,ans); return ; } for(var i=index;i<len;i++){ if(sum+candidates[i]>target) continue; res.push(candidates[i]); dfs(i,sum+candidates[i],candidates,target); res.pop(); } } var combinationSum = function(candidates, target) { ans=[]; len=candidates.length; candidates.sort((a,b)=>a-b); for(var i=0;i<len;i++){ res=[candidates[i]]; dfs(i,candidates[i],candidates,target); } return ans; };
方法一:正则实现
//正则实现 function format (num) { var reg=/\d{1,3}(?=(\d{3})+$)/g; return num.toString().replace(reg, '$&,'); } //基础 function format(num){ num+=''; var str=""; for(var i=num.length-1,j=1;i>=0;i--,j++){ if(j%3===0 & i!=0){ str+=num[i]+','; }else{ str+=num[i]; } } return str.split('').reverse().join(''); }
方法二:for循环正常思惟算法
function format(num){ num=num+'';//数字转字符串 var str="";//字符串累加 for(var i=num.length- 1,j=1;i>=0;i--,j++){ if(j%3==0 && i!=0){//每隔三位加逗号,过滤正好在第一个数字的状况 str+=num[i]+",";//加千分位逗号 continue; } str+=num[i];//倒着累加数字 } return str.split('').reverse().join("");//字符串=>数组=>反转=>字符串 }
方法三:slice+while循环
function format(num) { var arr = [], str = num + '', count = str.length; while (count >= 3) { arr.unshift(str.slice(count - 3, count)); count -= 3; } // 若是是否是3的倍数就另外追加到上去 str.length % 3 && arr.unshift(str.slice(0, str.length % 3)); return arr.toString(); }
方法四:reduce版
function format(num) { var str = num+''; // ["8", "7", "6", "5", "4", "3", "2", "1"] return str.split("").reverse().reduce((prev, next, index) => { return ((index % 3) ? next : (next + ',')) + prev; }) } console.log(format(12345678));
设三只变色龙分别为x y z当任意两只相遇边恒另一只时,其变换成课简化为:(x-n)(y-n) (z+zn) n= 0,1,2,...
其中n =0 表明没有穿绳变化的状况。那么只要变化后知足下述三种情形之一,则表明能够变成同一种颜色:
x-n = y-n
x-n = z+2n
y-n = z+2n
(即,有两种颜色的变色龙数量相等时,可所有变为第三种颜色)
解答方程可得:
上述三种状况实质上能够用一种状况表明:
x-y = 3n (n =0,1,2,....)
即,三种变色龙中,任意两种的数量相乘为3的倍数时,便可变成为同一种颜色的变色龙。
参考地址:https://blog.csdn.net/qq_32657025/article/details/79599954
对前端将来有什么见解
简单介绍下本身
讲讲项目,碰见比较有趣的点,遇到的困难 (快手)
你还面过哪些公司呢?有offer吗?
用三句话简单评价一下你本身
如何看待加班
将来职业规划
在与后台沟经过程中,碰见过什么困难?如何联调?
自我介绍
印象最深入的一个项目,为何,这个项目给你的最大的收获是啥?
近期遇到的最大的困难是啥?如何解决?期间是如何努力的?
最近印象最深入的事情是啥?
学习能力强的缘由是啥?
有什么业余爱好?
最近去哪些地方玩过?
若是老板提一个很难实现的需求,如何解决?
银行和互联网的区别,为啥想要到银行工做?
若是银行和互联网同时给你offer,怎么选?
为何不留原公司,原公司有哪些地方让你想吐槽?如何解决这些问题?会找领导主动反馈吗?
以为原公司有啥不合理的
有别的offer吗? 若是面临多个offer选择,你会怎么考虑?(腾讯)
讲讲项目,碰见比较有趣的点,遇到的困难(快手)
此处没有标准答案,由于每一个人的状况不一样,你们多面几回这些问题都应该不是问题了。
还有2件事拜托你们
一:求赞 求收藏 求分享 求留言,让更多的人看到这篇内容
二:欢迎添加个人我的微信
备注“资料”, 300多篇原创技术文章,海量的视频资料便可得到
备注“加群”,我会拉你进技术交流群,群里大牛学霸具在,哪怕您作个潜水鱼也会学到不少东西
金三银四,磨砺锋芒;剑指大厂,扬帆起航(2020年最全大厂WEB前端面试题精选)上
金三银四,磨砺锋芒;剑指大厂,扬帆起航(2020年最全大厂WEB前端面试题精选)中
金三银四,磨砺锋芒;剑指大厂,扬帆起航(2020年最全大厂WEB前端面试题精选)下