GitHub Repo:coderZsq.target.swift
Follow: coderZsq · GitHub
Resume: coderzsq.github.io/coderZsq.we…前端
前段日子寫了篇面經, 獲得了掘金
的徵文活動
的三等獎
仍是很是開心, 可是被寒神說面試不過就泄題
, 影響很差, 我想一想也是, 立刻就把大廠的名字給抹掉
了, 但被轉載的就無能爲力
了, 看到下面好多噴的, 真是背後一涼, 一首涼涼送給本身, 形成的傷害沒法挽回, 再此鄭重道歉, 不再寫面經了. 但願之後還能得到大廠面試
的機會!python
被大廠
刷掉後, 我心情難以平復, 由於其實我是作了充足的準備
來的, 可是仍是實力上有差
距, 誒... 仍是想一想改如何提高
本身的水平吧!webpack
其實對於本身, 我其實並不知道iOS
該如何進行學習, 也不知道技術這條路
我半道轉的是否是正確, 更不知道在當今環境下我這種水平的iOS
開發者是否還有存在的必要.c++
提及轉行作iOS
到如今, 從Objective-C
基礎語法學起, 認爲OC
是最好的語言, 學會作幾個簡單的UITableView
頁面, 能播放音頻視頻
, 以爲本身真是轉了個高大上的職業
, 如今想一想, 真是膚淺
的讓人忍不住發笑.git
我把作iOS
這段學習經歷分爲五個階段:程序員
第一個階段: 是剛剛轉行進入互聯網企業, 那時候以爲學好CALayer
掌握了一些酷炫的動畫(貝塞爾曲線
), 感受就已經比大多數人都強了, 那時候還把經常使用的工具類封裝起來, 就以爲, 嗯, 本身還不錯.github
第二個階段: 就是瞎學些有的沒的, 如Swift
, JavaScript
, Java
什麼的, 以爲本身全棧了, 什麼都會了, 很牛逼, 你看還本身可以寫一個前端簡歷, 還作過公司的前端項目, 服務器開發也會了, 自信心爆棚啊, 以爲本身真是無所不能.web
第三個階段: 寫了一個架構生成器
, 以爲本身所向披靡
了, 公司項目都在用我寫的架構, 用着我制定的規則
, 尼瑪不就是一個簡單的字符串替換
, 嘚瑟個啥... 並且對於架構的理解膚淺至極
...面試
第四個階段: 察覺到了本身的薄弱, 開始學習iOS
的底層原理, 學習了C\C++
的語法, 學習了Linux
基礎, 學習了8086, ARM64
彙編, 瞭解了一些自認爲
仍是比較深的知識點. 以爲本身前途仍是有但願的.算法
第五個階段: 也就是被刷掉以後的如今, 其實我如今也很迷茫, 也不知道如今學的東西到底有沒有用, 也不知道大廠到底要什麼樣的人才(只知道牛逼就行...), 但我也經過把知識點進行分類進行進階吧. 把最近的學習總結分享出來和你們一塊兒討論, 像我這種水平的玩家到底該怎麼玩耍.
我把最近學習的方面所有都整理在StudyNote
這個裏面了, 能夠看得出, 這個階段, 我明顯的就是像要學習增強算法與數據結構
方面的, 多是由於被大廠刷的有陰影了吧.
除了數據結構與算法
, 最近剛看完的CS193p
的教程, 白鬍子老頭的這個視頻的質量很高
, 發現了不少我平時忽略的東西, 並且以爲不少我覺得的寫法從本質上
都是有問題的.
還有就是objc.io
的這幾本書了, 質量挺高的, 函數式Swift
的學習對我頗有幫助. 感受就像是打開了新世界.
還有就是排在後面的學習計劃: python
, 數據分析
, 機器學習
, 深度學習
.能夠看得出, 其實這些都學完, 其實也不知道可以幹什麼, 無所事事誒... 但至少這些都是我可以找到的比較高質量
的資料了, 若是有其餘高質量的資料, 歡迎進行資料共享hhhh~
果真, 算法是擋在(複製黏貼
)程序員和(正常
)程序員以前的一條很難跨越的鴻溝, 我這裏不是說, 你會寫快速排序
,二分查找
, 深度廣度優先
這類你們都可以背出來的東西就叫作掌握算法了, 我在Coursera
上看了加州大學
的算法課, 才知道該如何設計算法, 但因爲是英語的, 並且沒有代碼, 純數學的看不太懂, 因此轉向了北京大學
的算法課, 如下就是我最新學到的算法和你分享.
這個只是算法基礎
的第二節課, 你能想象這是算法基礎麼? 光是這個題目, 我就看了老半天, 大意是點擊一個燈, 上下左右的燈會自動點亮(熄滅)
, 當隨機給出點亮熄滅數的時候, 須要算出點擊哪幾個燈能夠將全部的燈點亮或熄滅.
這種算法題, 真是聞所未聞見所未見吧
, 並且這是算法基礎的開頭的課... 我在想難道那些大廠的人作這種題跟玩的同樣
麼, 想起了面試官的微笑
, 那可真是有力量的微笑呢.
#include <stdio.h>
int puzzle[6][8], press[6][8];
/* 推測驗證過程: 根據第一行猜想 */
bool guess() {
int c, r;
//根據press第1行和puzzle數組,計算press其餘行的值
for(r=1; r<5; r++) {
for(c=1; c<7; c++) {
press[r+1][c]=(puzzle[r][c]+press[r][c]+press[r-1][c]+press[r][c-1]+press[r][c+1])%2;
}
}
//判斷所計算的press數組可否熄滅第5行的全部燈
for(c=1; c<7; c++) {
if ((press[5][c-1]+press[5][c]+press[5][c+1]+press[4][c])%2 != puzzle[5][c]) {
return false;
}
}
return true;
}
/* 枚舉過程: 對press第1行的元素press[1][1]~press[1][6]的各類取值進行枚舉 */
void enumerate() {
int c;
bool success; //這個變量時當時定義了沒排上用場吧,NodYoung注
for(c=1; c<7; c++) {
press[1][c]=0;
}
while(guess()==false) {
press[1][1]++;
c=1;
while(press[1][c]>1) { //累加進位
press[1][c]=0;
c++;
press[1][c]++;
}
}
return ;
}
int main() {
int cases, i, r, c;
scanf("%d", &cases);
for(r=0; r<6; r++) {
press[r][0]=press[r][7]=0;
}
for(c=0; c<7; c++) {
press[0][c]=0;
}
for(i=0; i<cases; i++) {
for(r=1; r<6; r++) {
for(c=1; c<7; c++) {
scanf("%d", &puzzle[r][c]); //讀入輸入數據
}
}
enumerate();
printf("PUZZLE#%d\n", i+1);
for (r=1; r<6; r++) {
for (c=1; c<7; c++) {
printf("%d ", press[r][c]);
}
printf("\n");
}
}
return 0;
}
複製代碼
這是北大老師
視頻裏給出的算法的答案, 講的很好, 可是說真的聽的是隻知其一;不知其二, 緣由在於不知道爲何, 這些網課都不是在線編譯
的, 而是直接對着代碼分析
, 上面的代碼摘抄自-> 能夠搜索熄燈問題
.
var puzzle = [[Int]](repeating: [Int](repeating: 0, count: 8), count: 6)
var press = [[Int]](repeating: [Int](repeating: 0, count: 8), count: 6)
複製代碼
func guess() -> Bool {
for r in 1..<5 {
for c in 1..<7 {
press[r + 1][c] = (puzzle[r][c] + press[r][c] + press[r - 1][c] + press[r][c - 1] + press[r][c + 1]) % 2
}
}
for c in 1..<7 {
if (press[5][c - 1] + press[5][c] + press[5][c + 1] + press[4][c]) % 2 != puzzle[5][c] {
return false
}
}
return true
}
複製代碼
func enumerate() {
var c = 1
for _ in 1..<7 {
press[1][c] = 0
while (guess() == false) {
press[1][1] += 1
c = 1
while press[1][c] > 1 {
press[1][c] = 0
c += 1
press[1][c] += 1
}
}
c += 1
}
}
複製代碼
class Enumerate {
static func main() {
let cases = 1
for r in 0..<6 {
press[r][0] = 0
press[r][7] = 0
}
for c in 1..<7 {
press[0][c] = 0
}
for i in 0..<cases {
for r in 1..<6 {
for c in 1..<7 {
puzzle[r][c] = 2.arc4random
}
}
enumerate()
print("PUZZLE #\(i + 1)")
for r in 1..<6 {
for c in 1..<7 {
print(puzzle[r][c], terminator: "")
}
print()
}
print("== press ==")
for r in 1..<6 {
for c in 1..<7 {
print(press[r][c], terminator: "")
}
print()
}
print()
}
}
}
複製代碼
以上是我學習的時候轉換成swift
表達的, 不爲何, 只是用來熟悉Swift
語法罷了, 畢竟OC
也不知道還能活個幾年了.
PUZZLE #1
011010
001110
010011
000101
100000
== press ==
001001
000101
001010
001101
011110
複製代碼
可是光看代碼, 很難看懂這個結果究竟是正確仍是不正確的... 由於跑出來是這樣的一個東西, 可是有些地方仍是能夠講一下, 好比是外面包了一圈0
來避免冗餘邏輯判斷, 用2進制
進位的方法進行運算, 仍是有學到一些皮毛的.
固然, 這種文字上的描述, 很難有深入的印象的, 因此, 我就在想是否能夠把這個熄燈遊戲給作出來, 再本身測試一下呢? 想到就幹吧!!
經過CS193p
的學習, 對於畫UI
方面有了全新的認識, 該如何添加約束, MVC
到底怎麼寫, 以致於我之前理解的感受徹底就是錯的, 正好趁這個機會來練練手.
咱們經過StoryBoard
先把View
畫好, 不得不說UIStackView
真是好用到爆!!
import Foundation
struct Matrix {
var rows: Int
var columns: Int
}
struct LightSwitch {
private var puzzle: [[Int]]
private var matrix: Matrix
var lights = [Int]()
mutating func lightUp(index: Array<Any>.Index?) {
guard let index = index else { return }
var m = Matrix(rows: 0, columns: 0)
if index <= matrix.rows {
m.columns = index + 1
} else {
m.columns += index % matrix.columns + 1
}
for i in 0...index {
if i % matrix.columns == 0 {
m.rows += 1
}
}
puzzle[m.rows][m.columns] = puzzle[m.rows][m.columns] == 0 ? 1 : 0
puzzle[m.rows + 1][m.columns] = puzzle[m.rows + 1][m.columns] == 0 ? 1 : 0
puzzle[m.rows][m.columns + 1] = puzzle[m.rows][m.columns + 1] == 0 ? 1 : 0
puzzle[m.rows - 1][m.columns] = puzzle[m.rows - 1][m.columns] == 0 ? 1 : 0
puzzle[m.rows][m.columns - 1] = puzzle[m.rows][m.columns - 1] == 0 ? 1 : 0
lights.removeAll()
for r in 1..<matrix.rows + 1 {
for c in 1..<matrix.columns + 1 {
lights.append(puzzle[r][c])
}
}
}
init(matrix: Matrix) {
self.matrix = matrix
puzzle = [[Int]](repeating: [Int](repeating: 0, count: matrix.columns + 2), count: matrix.rows + 2)
for r in 1..<matrix.rows + 1 {
for c in 1..<matrix.columns + 1 {
puzzle[r][c] = 2.arc4random
lights.append(puzzle[r][c])
}
}
print("========")
for r in 0..<matrix.rows + 2 {
for c in 0..<matrix.columns + 2 {
print(puzzle[r][c], terminator: "")
}
print()
}
print("========")
}
}
複製代碼
Model
代碼, 原來MVC
的M
須要這樣寫的, 之前都只是認爲是簡單的數據結構來的
真是膚淺, 這種直接業務邏輯寫在M
裏面的的寫法真是好用到爆啊!
import UIKit
extension UIColor {
var toImage: UIImage {
let bounds = CGRect(origin: .zero, size: CGSize(width: 1.0, height: 1.0))
let renderer = UIGraphicsImageRenderer(bounds: bounds)
return renderer.image { context in
self.setFill()
context.fill(CGRect(x: 0.0, y: 0.0, width: 1.0, height: 1.0))
}
}
}
extension Int {
var arc4random: Int {
if self > 0 {
return Int(arc4random_uniform(UInt32(self)))
} else if self < 0 {
return -Int(arc4random_uniform(UInt32(self)))
} else {
return 0
}
}
}
class ViewController: UIViewController {
@IBOutlet var lights: [UIButton]! {
didSet {
for (index, light) in lights.enumerated() {
light.setBackgroundImage(UIColor.yellow.toImage, for: .normal)
light.setBackgroundImage(UIColor.darkGray.toImage, for: .selected)
light.isSelected = switchs.lights[index] == 1 ? true : false
}
}
}
@IBAction func lightUp(_ sender: UIButton) {
switchs.lightUp(index: lights.index(of: sender))
for (index, light) in lights.enumerated() {
light.isSelected = switchs.lights[index] == 1 ? true : false
}
if Set(switchs.lights).count == 1 {
let alert = UIAlertController(title: "Congratulation", message: "You made all light up successfully", preferredStyle: .alert)
alert.addAction(UIAlertAction(
title: "again",
style: .default,
handler: { [weak self] _ in
self?.restart()
}
))
present(alert, animated: true)
}
}
@IBAction func restart(_ sender: UIButton? = nil) {
switchs = LightSwitch(matrix: Matrix(rows: 5, columns: 6))
for (index, light) in (self.lights.enumerated()) {
light.isSelected = self.switchs.lights[index] == 1 ? true : false
}
}
var switchs: LightSwitch = LightSwitch(matrix: Matrix(rows: 5, columns: 6))
}
複製代碼
Controller
的代碼, 這纔可以真正理解什麼叫作控制器用來協調View
和Model
的交互, Model
和View
毫無關聯, 這纔是iOS
的正確寫法啊.
運行了一下, 果真白鬍子大叔沒有騙我, 跑的6到飛起
~
能夠看到的是, 終端打印的矩陣和界面上顯示的是一一對應的, 從北大老師
學到的外面包一圈的方法也是特別好用的.
init(matrix: Matrix) {
self.matrix = matrix
puzzle = [[Int]](repeating: [Int](repeating: 0, count: matrix.columns + 2), count: matrix.rows + 2)
for r in 1..<matrix.rows + 1 {
for c in 1..<matrix.columns + 1 {
// puzzle[r][c] = 2.arc4random
puzzle[1][1] = 1
lights.append(puzzle[r][c])
}
}
print("========")
for r in 0..<matrix.rows + 2 {
for c in 0..<matrix.columns + 2 {
print(puzzle[r][c], terminator: "")
}
print()
}
print("========")
}
複製代碼
咱們將初始狀態從隨機數改爲只暗一個燈, 位置是[1][1]
class Enumerate {
static func main() {
let cases = 1
for r in 0..<6 {
press[r][0] = 0
press[r][7] = 0
}
for c in 1..<7 {
press[0][c] = 0
}
for i in 0..<cases {
for r in 1..<6 {
for c in 1..<7 {
// puzzle[r][c] = 2.arc4random
puzzle[1][1] = 1
}
}
enumerate()
print("PUZZLE #\(i + 1)")
for r in 1..<6 {
for c in 1..<7 {
print(puzzle[r][c], terminator: "")
}
print()
}
print("== press ==")
for r in 1..<6 {
for c in 1..<7 {
print(press[r][c], terminator: "")
}
print()
}
print()
}
}
}
複製代碼
咱們把北大算法
也改爲對應的[1][1]
PUZZLE #1
100000
000000
000000
000000
000000
== press ==
000111
101010
101100
001000
110000
複製代碼
能夠看懂只要按下所有位置對應爲1
的按鈕就能夠將全部燈都打開了, 咱們來試一下.
爲了避免用每次都跑到另外一個程序去運行算法, 我新增了Hint
提示功能, 每盤遊戲均可以點擊提示, 看到提示顯示的深色按鈕點擊對應位置的燈, 便可點亮全部的燈.
添加這個功能其實也很簡單, 只須要新建一個Popver
控制器便可, 使用對應算法, 映射到向量
便可.
import UIKit
class HintViewController: UIViewController {
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
if let fittedSize = topLevelView?.sizeThatFits(UILayoutFittingCompressedSize) {
preferredContentSize = CGSize(width: fittedSize.width + 30, height: fittedSize.height + 30)
}
}
override func viewDidLoad() {
super.viewDidLoad()
if presentationController is UIPopoverPresentationController {
view.backgroundColor = .clear
}
}
@IBOutlet var hints: [UIButton]! {
didSet {
for (index, hint) in hints.enumerated() {
hint.setBackgroundImage(UIColor.yellow.toImage, for: .normal)
hint.setBackgroundImage(UIColor.darkGray.toImage, for: .selected)
hint.isSelected = switchs?.hints[index] == 1 ? true : false
}
}
}
@IBOutlet weak var topLevelView: UIStackView!
var switchs: LightSwitch?
}
複製代碼
新增控制器, 就是顯示提示的控制器
@IBOutlet weak var hintButton: UIButton!
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "Show Hint", let destination = segue.destination.contents as? HintViewController,
let ppc = destination.popoverPresentationController {
ppc.delegate = self
ppc.sourceRect = hintButton.bounds
destination.switchs = switchs
}
}
func adaptivePresentationStyle(for controller: UIPresentationController, traitCollection: UITraitCollection) -> UIModalPresentationStyle {
return .none
}
複製代碼
原先控制器的Segue
設置, 讓iphone
默認不適配
mutating func guess() -> Bool {
for r in 1..<matrix.rows {
for c in 1..<matrix.columns + 1 {
press[r + 1][c] = (puzzle[r][c] + press[r][c] + press[r - 1][c] + press[r][c - 1] + press[r][c + 1]) % 2
}
}
for c in 1..<matrix.columns + 1 {
if (press[matrix.rows][c - 1] + press[matrix.rows][c] + press[matrix.rows][c + 1] + press[matrix.rows - 1][c]) % 2 != puzzle[matrix.rows][c] {
return false
}
}
return true
}
mutating func enumerate() {
var c = 1
for _ in 1..<matrix.columns + 1 {
press[1][c] = 0
while (guess() == false) {
press[1][1] += 1
c = 1
while press[1][c] > 1 {
press[1][c] = 0
c += 1
press[1][c] += 1
}
}
c += 1
}
}
複製代碼
在Model
中加入核心算法便可
這個Demo
多是全網惟一的熄燈問題
的UI
版本吧, 給本身一個贊~
通過好幾回測試, 能夠看見, 算法是正確
的, 我也學到了這個算法背後的思惟
, 更經過了寫了一個Demo
來證實了算法的正確性. 這個Demo
的難點在於向量
和矩陣
之間的互相轉換, 這裏爲何不說一維數組
和二維數組
呢? , 緣由在於吳恩達
的機器學習課程中也教會了我一些比較厲害的算法, 好比梯度降低
之類的.
好了, 如今寫文章沒有以前頻繁了, 緣由在於以前那些文章都太水
, 太膚淺
, 寫了對本身也沒有太大的意義, 被人看到也只會以爲是垃圾而已... 因此在我第五階段的學習
後, 但願可以有機會進入一家大廠繼續深造吧!
最後 本文中全部的源碼均可以在github上找到:
GitHub Repo:coderZsq.target.swift
Follow: coderZsq · GitHub
Resume: coderzsq.github.io/coderZsq.we…