「ARTS」 是一個學習打卡活動,發起人是骨灰級程序員陳皓,網名左耳朵耗子。任務是作一道 LeetCode 算法題(Algorithm)、閱讀並點評一篇英文技術文章(Review)、學習一個技術技巧(Tip),或分享一篇有觀點和思考的技術文章(Share),都是基於學習和思考的刻意練習。html
共勉java
一苦一樂相磨鍊,煉極而成福者,其福始久;一疑一信相參勘,勘極而成知者,其知始真。——《菜根譚》程序員
在講解算法題以前,先補充一個知識點:算法的時間與空間複雜度算法
咱們評價一個算法的優劣主要從兩個維度來考量:編程
時間維度:是指執行當前算法所消耗的時間,咱們一般用「時間複雜度」來描述。數組
空間維度:是指執行當前算法須要佔用多少內存空間,咱們一般用「空間複雜度」來描述。安全
1.時間複雜度markdown
時間複雜度的表示方法:大 O 符號表示法,即 T(n)=O(f(n))app
這個公式被稱爲:算法的漸進時間複雜度框架
f(n)
表示每行代碼的執行次數之和,而 O
表示正比例關係。來看一個具體的例子:
for (int i = 0; i < n; i++) {
j = i;
j++;
}
複製代碼
上面一共 4 行代碼,咱們假設每一行代碼的執行時間是同樣的,咱們用 一顆粒時間 來表示。
第一行代碼的執行耗時:n 個顆粒時間 第二行代碼的執行耗時:n 個顆粒時間 第三行代碼的執行耗時:n 個顆粒時間 第四行代碼的執行耗時:是符號,暫時忽略
總的時間:T(n) = 3n * 顆粒時間。從這個耗時能夠看出,總的執行時間是隨着 n 的變化而變化,所以,咱們能夠簡化一下這個算法的時間複雜度表示:T(n) = O(n)
。
之因此能夠簡化,是由於大 O 符號表示法並非用來表示算法真實的執行時間,它是用來表示代碼執行時間的增加變化趨勢的。
常見的時間複雜度量級有:
上面從上至下依次的時間複雜度愈來愈大,執行的效率愈來愈低。
2.空間複雜度
明白了時間複雜度,那麼空間複雜度也是相似的。空間複雜度也不是用來計算程序實際佔用的空間的。
空間複雜度是對一個算法在運行過程當中臨時佔用存儲空間大小的一個量度,一樣反映的是一個趨勢。
空間複雜度比較經常使用的有:O(1)、O(n)、O(n²)
來看兩個例子:
int i = 1;
int j = 2;
int sum = i + j;
複製代碼
代碼裏的 i 和 j 所分配的空間不會隨着處理數據量而變化,所以它的空間複雜度 S(n) = O(1)
。
第二個例子:
int[] m = new int[n];
for (int i = 0; i < n; i++) {
j = i;
j++;
}
複製代碼
在第一行代碼中,經過 new 關鍵字建立了一個數組出來,數組 m 佔用的大小爲 n ,第 2 到第 5 行代碼雖然是一個循環,可是沒有再分配新的空間,所以,上述代碼的空間複雜度是:S(n) = O(n)
。
本期算法
給定一個整數數組 nums 和一個整數目標值 target,請你在該數組中找出 和爲目標值 的那 兩個 整數,並返回它們的數組下標。
你能夠假設每種輸入只會對應一個答案。可是,數組中同一個元素在答案裏不能重複出現。 你能夠按任意順序返回答案。
示例1:
輸入:nums = [2,7,11,15], target = 9
輸出:[0,1]
解釋:由於 nums[0] + nums[1] == 9 ,返回 [0, 1] 。
複製代碼
示例2:
輸入:nums = [3,2,4], target = 6
輸出:[1,2]
複製代碼
示例3:
輸入:nums = [3,3], target = 6
輸出:[0,1]
複製代碼
解題思路
最直接的方法是採用 暴力枚舉法
,用兩個 for 循環來遍歷兩個數相加,等於 target 就返回兩個數的下標,代碼以下:
class Solution {
public int[] twoSum(int[] nums, int target) {
int n = nums.length;
for (int i = 0; i < n; ++i) {
for (int j = i + 1; j < n; ++j) {
if (nums[i] + nums[j] == target) {
return new int[]{i, j};
}
}
}
return new int[0];
}
}
複製代碼
複雜度分析
時間複雜度:O( )
空間複雜度:O(1)
方法二:哈希表
class Solution {
public int[] twoSum(int[] nums, int target) {
Map<Integer, Integer> map = new HashMap<>();
for (int i = 0; i < nums.length; i++) {
if (map.containsKey(target - nums[i])) {
return new int[]{map.get(target - nums[i]), i};
}
map.put(nums[i], i);
}
return new int[0];
}
}
複製代碼
首先建立一個 HashMap,用來存放遍歷過的元素。而後使用一個 for 循環來遍歷數組,內部判斷 HashMap 中是否包含了 target - x
,若是包含直接返回下標,若是不包含,則將該元素存入 HashMap,用元素的值作 key,下標作 value。
複雜度分析
時間複雜度:O(N)。其中 N 是數組中的元素數量。對於每個元素 x,咱們能夠 O(1) 地尋找 target - x
。
空間複雜度:O(1)
本期的文章來自 Medium。
原文:These 10 Flutter Widgets Every Developer Should Know
本文主要介紹了 Flutter 開發中經常使用的 10 個基礎 Widget。
做者選取的這 10 個 Widget 對於實際開發來講仍是很實用的,每個 Widget 都能針對性的解決一些問題,而且在實際使用中也很簡單而且穩定。
固然,在真實的項目中,確定不止這 10 個 Widget,不過就像做者在開篇寫的同樣:programming is a field that you should practice or getting to know something about daily(編程是一個須要天天實踐或者學習一點東西的領域)。
咱們能夠以這 10 個 Widget 做爲基礎,天天學習一點新知識,不斷壯大本身的知識體系。
使用 Dart 的兩個技巧
1.Use the call Method To Make Classes Callable Like a Function
使用 call 方法讓類像函數同樣能夠被調用
定義一個類:
class CallMethodDemo {
// Defining call method
String call(String name) => 'hello $name';
}
複製代碼
使用:
void main() {
var call_input = CallMethodDemo();
// Calling the class through its instance
var call_output = call_input('jack');
print(call_output);
}
複製代碼
這種讓實例像函數那樣被直接調用的類,稱爲 callable class
。
注意:一個類只容許有一個 call 方法
2.Use entries To Iterate Through a Map
使用 entries 來遍歷 map 集合
for (var entry in moneySpent.entries) {
// do something with keys and values
print('${entry.key}: ${entry.value}');
}
複製代碼
保證空安全。
文章連接:Flutter state management for minimalists
狀態管理一直是響應式編程中一個繞不開的話題。目前 Flutter 有不少狀態管理的框架,好比 Provider、Bloc、Redux、MobX 等等。
這篇文章的目的並非對比每一個框架的優缺點,而是試圖去解釋清楚什麼是狀態管理。
學習了這篇文章再去理解各個狀態管理框架的話,應該能有所收穫。