面試算法(一)

  • 寫一個簡單的死鎖程序:
#include <iostream>
#include <thread>
#include <mutex>
using namespace std;

int data = 1;
mutex mut1,mut2;

void fun2() {
    data = 20;
    mut1.lock();  //第二次申請對mut1上鎖,失敗
    cout << data << endl;
    mut1.unlock();
}
void fun1() {
    mut1.lock();  //第一次對mut1上鎖
    data = 30;
    fun2();
    cout << data << endl;
    mut1.unlock();
}

int main() {
    cout << "I'm here!" << endl;
    thread thr1(fun1);
    thr1.join();
    cout<<"I'm here now!"<<endl;
    return 0;
}

  • 寫一個類似 printf 的可以接受任意類型,任意個數的打印函數
#include <iostream>

void show_list() { }	//遞歸的終止條件,args 爲 0

template <typename T>	//單獨處理最後一個參數,換行而不是 ,
void show_list(const T &value) {
    std::cout << value << std::endl;
}

template <typename T, typename... Args>
void show_list(const T &value, const Args &...args) {
    std::cout << value << ",";
    show_list(args...);
}

int main() {
    int n = 19;
    std::string s = "kjfdh";
    double f = 1.11123;
    show_list(n, f, s);
    return 0;
}

  • 問:用預處理指令計算一年有多少秒
#include <iostream>
#define Year_Second (365UL*24*3600UL)
using namespace std;

// 此方法不會影響運行性能
// 宏不僅僅是字符替換而已
// 一般的編譯器會把能計算出來的宏(無參數或參數爲常量)計算爲最後的結果

int main() {
    cout << Year_Second << endl;
    return 0;
}

  • 問題:判斷給定的 ip 是否合法
#include <iostream>
#include <regex>
using namespace std;

bool isValid(const string &ip) {
    string ts;
    bool ans = true;
    regex add("[0-9]|[1-9][0-9]|[1-2][0-4][0-9]|25[0-5]");
    for(int i =0; i < ip.length(); i++) {
        if(ip[i]!='.') ts+=ip[i];
        else {
            ans = regex_match(ts, add);
            if(!ans) return false;
            cout << "ts = " << ts << "  : " << ans << endl;
            ts = "";
        }
    }
    return ans;
}

int main() {
    string ip;
    while(cin >> ip) {
        regex address("[0-9]+.[0-9]+.[0-9]+.[0-9]+");
        if(!regex_match(ip, address))  {
            cout << "false" << endl;
            continue;
        } else {
            string tip  = ip;
            tip += ".";	// 爲了方便 isValid 函數統一處理,可以一依據'.'提取出每個數字段
            cout << isValid(tip) << endl;
        }
    }
    return 0;
}

  • 問題: 給定 N 個數, 判斷數組中是否包含重複數字
#include<iostream>
#include<ctime>
using namespace std;

//判斷數組中是否包含重複數字
bool isDuplicate(int val[], int n) {
    for(int i=0;i<n;i++) {
        if(val[i]!=i) {
            if(val[i] != val[val[i]])
                swap(val[i],val[val[i]]);
            else
                return true;
        }
    }
    return false;
}

int main() {
    int n;
    while(cin >> n) {
        int val[n];
        srand((unsigned)time(NULL));

        cout<<"init data:"<<endl;
        for(int i=0;i<n;i++) {
            int tmp=rand()%n;
            val[i]=tmp;
            cout<<tmp<<" ";
        }
        cout<<endl;
        bool flag=isDuplicate(val, n);

        if(flag)
            cout << "has duplicate elem" << endl;
        else
            cout << "no duplicate elem" << endl;
    }
    return 0;
}
  • 問題: 素數篩選法:給定 N , 輸出 [ 1, N ] 的所有素數
#include <iostream>
#include <cmath>
#define Max_n 100001
using namespace std;

bool isPrime[Max_n];

int main() {
    // 先把所有奇數小標的標爲 true; 
    // 把所有偶數小標的標爲 false;
    for(int i = 0; i < Max_n; i++) {
        if(i%2) isPrime[i] = true;
        else isPrime[i] = false;
    }
    isPrime[2] = true;

    int n_sqrt = floor(sqrt(double(Max_n)));
    cout << n_sqrt << endl;
    for(int i = 3; i <= n_sqrt; i+=2) {
        if(isPrime[i]) {
            for(int j = 2*i; j <= Max_n; j+=i) {
                isPrime[j] = false;
            }
        }
    }

    int n;
    int counts = 0;
    while(cin >> n) {
        for(int i = 0; i < n; i++) {
            if(isPrime[i]) {
                counts++;
                cout << i << " ";
            }

        }
        cout << "counts = " << counts << endl;
        cout << endl;
    }
    return 0;
}
  • 問題:輸出一個單鏈表的倒數第 k 個節點
  • 細節:尾部插入法, 頭節點,快慢指針
#include <iostream>
using namespace std;

struct ListNode {
    int m_nKey;
    ListNode* m_pNext;
};

ListNode* FindKthToTail(ListNode* pListHead, unsigned int k) {
    ListNode *pFast, *pLow;
    pFast = pLow = pListHead;
    for(int i = 0; i < k; i++) {
        pFast = pFast->m_pNext;
    }
    while(pFast) {
        pFast = pFast->m_pNext;
        pLow = pLow->m_pNext;
    }
    return pLow;
}

int main() {
    int k, n;
    while(cin >> n && n) {
        ListNode *pHead = new ListNode;
        pHead->m_nKey = n;
        pHead->m_pNext = NULL;
        ListNode *pTail = pHead;
        for(int i = 0; i < n; i++) {
            ListNode *tmpNode = new ListNode;
            cin >> tmpNode->m_nKey;
            tmpNode->m_pNext = NULL;
            pTail->m_pNext = tmpNode;
            pTail = tmpNode;
        }

        cin >> k;
        ListNode *p = pHead->m_pNext;
        while(p) {
            cout << p->m_nKey << " ";
            p = p->m_pNext;
        }
        cout << endl;
        p = pHead->m_pNext;
        if(k > n) {
            return 0;
        } else {
            ListNode *ptr = new ListNode;
            ptr = FindKthToTail(p, k);
            if(!ptr)
                cout << ptr->m_nKey << endl;
        }
    }
    return 0;
}

  • 問:走出迷宮,從左上角開始,右下角離開,輸出最短路徑
#include <iostream>
#include <queue>
#define max_s 10
using namespace std;

typedef struct points {
    int x;
    int y;
}Point;

int n, m;
Point pre[max_s][max_s]; //記錄路徑
int maze[max_s][max_s]; //迷宮信息
bool vis[max_s][max_s]; //是否走過
int dir[4][2] = {{1,0},{-1,0},{0,1},{0,-1}};

//打印路徑
void myPrint(Point cur) {
    if(cur.x == 1 && cur.y == 1) {
        cout << "(0,0)" << endl;
        return ;
    }
    myPrint(pre[cur.x][cur.y]);
    cout << "(" << cur.x-1 << "," << cur.y-1 << ")" << endl;
}

// maze[1][1] 到 maze[n][m] 的最短路徑
void bfs(int x, int y) {
    //初始化隊列
    queue<Point> que;
    Point sPoint;
    sPoint.x = x;
    sPoint.y = y;
    //start_Point & now_Point,並把起點壓入隊列
    que.push(sPoint);
    vis[x][y] = true; //起點被走過了
    while(!que.empty()) {
        Point nPoint = que.front();
        que.pop();
        if(nPoint.x == n && nPoint.y == m) {
            myPrint(nPoint);
            break;
        }
        // 探索四個方向
        for(int i = 0; i < 4; i++) {
            int nx = nPoint.x + dir[i][0];
            int ny = nPoint.y + dir[i][1];
            //檢查是否越過邊界
            if(nx>=1 && nx<=n && ny>=1 && ny<=m
            && maze[nx][ny]==0 && !vis[nx][ny]) {
                vis[nx][ny] = true;
                Point newPoint;
                newPoint.x = nx;
                newPoint.y = ny;
                que.push(newPoint);
                pre[newPoint.x][newPoint.y] = nPoint; //記錄前驅節點
            }
        }
    }
}

int main() {
    while(cin >> n >> m) {
        fill(vis[0], vis[0]+max_s*max_s, false); //初始化都沒走過
        fill(maze[0], maze[0]+max_s*max_s, 0); //初始化迷宮都爲 0
        //輸入迷宮
        for(int i = 1; i <= n; i++)
            for(int j = 1; j <= m; j++)
                cin >> maze[i][j];

        bfs(1, 1);
    }
    return 0;
}

  • 排列組合:求 A(n, m) 和 C(n, m):
#include <iostream>
using namespace std;

long long getA(int n, int m) {
    if(n < m) return 0;
    long long ans = 1;
    while(m--) {
        ans *= n;
        n--;
    }
    return ans;
}

long long getC(int n, int m) {
    if(n < m) return 0;
    return getA(n, m)/getA(m, m);
}

int main() {
    int n, m;
    while(cin >> n >> m) {
        cout << getA(n, n) << endl << getA(m, m) << endl;
        cout << getC(n, m) << endl;
    }
    return 0;
}

  • 輸出 n 個數中最小的 k 個數,包含交換函數,指針傳遞,k 趟選擇排序
#include <iostream>
using namespace std;

void mySwap(int *a, int *b) {
    int tmp = *a;
    *a = *b;
    *b = tmp;
}

// 核心算法:選擇排序
bool GetMinK(unsigned int uiInputNum, int *pInputArray, unsigned int uiK, int *pOutputArray) {
    if(uiK < 1 || uiK > uiInputNum)
        return false;

    for(int i = 0; i < uiK; i++) {
        for (int j = i+1; j < uiInputNum; j++) {
            if(pInputArray[i] > pInputArray[j]) {
                mySwap(&pInputArray[i], &pInputArray[j]);
            }
        }
        pOutputArray[i] = pInputArray[i];
        cout << pOutputArray[i] << endl;
    }

    return true;
}

int main() {
    unsigned int n, k;
    while(cin >> n >> k) {
        int nums[n];
        int res[k];
        for(int i = 0; i < n; i++) {
            cin >> nums[i];
        }
        bool ans = GetMinK(n, nums, k, res);
        if(ans) {
            for(int i = 0; i < k - 1; i++)
                cout << res[i] << " ";
            cout << res[k-1] << endl;
        }
    }
    return 0;
}

問:求二元一次方程:

#include <iostream>
using namespace std;

int main() {
    int t;
    cin >> t;
    while(t--) {
        int a[3], b[3], c[3];
        cin >> a[1] >> b[1] >> c[1] >> a[2] >> b[2] >> c[2];
        int m = a[1]*b[2]-b[1]*a[2];
        if(m==0) {
            cout << "Unknown" << endl;
        } else {
            int p1 = c[1]*b[2]-c[2]*b[1];
            int p2 = a[1]*c[2]-c[1]*a[2];
            double x = (p1*1.0)/(m*1.0);
            double y = (p2*1.0)/(m*1.0);
            cout << x << " " << y << endl;
        }
    }
    return 0;
}

問:求最小連續子序列和:

#include <iostream>
#include <algorithm>
using namespace std;

int main() {
    int n;
     while(cin >> n) {
         int nums[n];
         int dp[n+1];
         fill(dp, dp+n+1, 0x3f3f3f);
         for(int i = 0; i < n; i++)
             cin >> nums[i];

         for(int i = 1; i < n; i++) {
             dp[i] = min(nums[i], dp[i-1]+nums[i]);
         }
         int ans = *min_element(dp, dp+n);
         cout << ans << endl;
     }
    return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章