元旦匆匆而過,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前端面試題精選)下