two sum(2)

below is a 0ms solution from leetcode
but it actually missed a test case
[50000000,3,2,4,28800,50000000]
100000000
this 0ms submission using a %TABLE_SIZE to shrink the table needed
but collision will happen!!

/**
 * Note: The returned array must be malloced, assume caller calls free().
 */
int* twoSum(int* nums, int numsSize, int target, int* returnSize){
    int i = 0;
    int j = 0;
    int *ret = NULL;
    int *returnSize = 2;
    for(i = 0 ; i<numsSize ; i++){
        for(j = i ; j= 0){
       return (key % TABLE_SIZE);
     }
     else{
       key = TWO_COMPLEMENT + key;
       return (key % TABLE_SIZE);
     }
}


// Our record table definition, an array of M records.

    //record_table = (Record *)malloc(sizeof(*record_table)*TABLE_SIZE);

// Insert function. Inserts record at the index determined by the hash
// function. Uses linear probing if already occupied.

void insert(Record *record_table,int value, int index){
     int idx = hash(value);
     record_table[idx].value = value;
     record_table[idx].index =  index; 
    // printf("insert table[%d] : %d, %d\n", idx, value, index);
}
// Search Function. Returns the record with a matching key. Search starts
// at the index determined by the hash function. Uses linear probing until
// the matching key is found. Returns NULL on search miss.
int search(Record *record_table,int value) {
   int idx = hash(value);
   //printf("search table[%d] : %d,%d\n", idx, record_table[idx].value,record_table[idx].index);
   if (record_table[idx].value == value ) {
        return record_table[idx].index;
   }
   else {
        return 0;
   }
}



/**
 * Note: The returned array must be malloced, assume caller calls free().
 */
int* twoSum(int* nums, int numsSize, int target, int* returnSize){
    
     
     
    //using hash of value, index
    
    int complement = 0;
   
    //Record record_table[TABLE_SIZE];
    Record *record_table;
    record_table = malloc(sizeof(record_table)*TABLE_SIZE);
    
    
    for(int i = 0; i  for every element in array, find complement with target in the rest of the array
    /*
    int complement = 0;
    int *arr;
    arr = malloc(sizeof(int)*2);
    
    for(int i = 0; i < numsSize; i++){
          arr[0] = i;
          complement = target - nums[i];
        
          for(int j = i+1 ; j < numsSize; j++ ){
              
              if(nums[j] == complement ){
                  arr[1] = j;
                  *returnSize = 2;
                  return arr;
              }   
          }
    }
    
    *returnSize = 0;
     return NULL;
    */

}

two sum

the very basic solution

/**
 * Note: The returned array must be malloced, assume caller calls free().
 */
int* twoSum(int* nums, int numsSize, int target, int* returnSize){
    int i, j;
    int *ret = NULL;
    *returnSize = 2;
    for(i=0 ; i<numsSize ; i++){
        for(j=i+1 ; j<numsSize ; j++){
            if(nums[i]+nums[j] == target){
                ret = (int*)malloc(2*sizeof(int));
                ret[0] = i;
                ret[1] = j;
                return ret;
            }
        }
    }
    return NULL;
}

會員關聯度,用標準差找出萬名會員中具有接近特徵的兩個人

真的是太強了

我朋友竟然把標準差(standard deviation)應用到生活日常上!

原本目的是要找出會員之間的關聯性,誰跟誰具有接近的特徵,並且又符合某些預設條件,例如性別年齡等等

這件事情最簡單的解法就是排列組合,列出全部的組合之後,一個一個檢查他們有哪些特徵符合,然後輸出特徵符合比例最高的一組

但是會員數量一大,例如一萬人

全部比對過一次需要的比較數量是Cn取2,如果有一萬人,就有49,995,000種組合

就會讓整個比對的時間拉到數天,時間長到無法提供正常服務

後來我們決定先計算出全部會員的特徵分數標準差,標準差高的人代表他在某個特徵比較明顯,也就是說他會是我們想要優先進行配對的人

而且排序找出標準差最高的人這件事情丟給資料庫做是一件非常簡單又快速的事情

找出標準差高的人之後,先列出這個人特徵最高分數是哪個種類以及幾分,再去針對該種類做排序找出也具有很高分數的人,即可完成配對。

以上讓整件事情從四千九百萬種組合降低到兩次排序完成

時間複雜度從N平方到2

超爽的阿~

 

比特幣:被放棄的那條 block chain 上面的交易該怎麼辦

一篇俄羅斯人分析比特幣寫的論文

https://dl.dropboxusercontent.com/u/3658181/PiotrPiasecki-BitcoinMasterThesis.pdf

個人最想了解的問題:出現分歧之後「被放棄的那條 block chain 上面的交易該怎麼辦」

這個問題還沒有解法

目前的答案應該是「被放棄的 block chain上面的交易被視為無效」

所以目前比特幣交易至少要等十分鐘之後才算完成(https://bitcoin.org/zh_TW/faq#why-do-i-have-to-wait-10-minutes)

也就是十分鐘之後交易才開始有被至少一個 Node 驗證

並且建議等待60分鐘,也就是產生了 6 個 block 之後才算保證安全

根據本論文紀錄 ,2012 年已知最長的被取消的區塊鍊長度為 4

 

有另一個資訊也非常有趣

論文第38頁

Reaching the current transaction volume of Visa (2000 transactions per second) would require a creation and propagation of 1.14GB Block each 10 minutes

也就是說如果要達到目前VISA的交易次數,每秒兩千次,每十分鐘生成的 block 會佔用1.14GB的空間,就網路傳輸來看,可以說跟本不可能達到比特幣設計初衷的將這個 block 散佈到所有 Node

The current implementation of the Bitcoin Protocol does not support such scalability. As a standard Transaction on average is at least 0.23kB in size and the maximum Block size is 1MB, the entire Block would be filled at most with 4348 Transactions. As each Block should be generated every 10 minutes, the Protocol can handle about 8 Transactions per second. The current peak usage of Bitcoin was about 14,000 Transactions in a day [124], averaging to about 0.16 Transactions per second

目前每一筆交易大約佔用 0.23KB 的空間,一個 block 大小為 1MB,平均一個 block 可以存放 4348 筆交易

並且每十分鐘才能產生一個 block ,也就是平均每秒可以處理至多 8 筆交易

目前平均一天有約 14,000 幣比特幣交易,平均每秒 0.16 筆

第44頁

Up to this date the longest Block Chain fork was 4 Blocks long

本篇論文撰寫的時候,最長的分歧也才4 個 block

也就是過去 40 分鐘內的交易失效了,我認為這時間並不短,而且交易失效非常嚴重

 

我是從http://bitcoin.stackexchange.com/a/4976/33824 這個連結發現這篇俄羅斯論文的

總結來說,目前針對 bitcoin 的缺陷能夠解決的辦法就是「等待」

「等待」一個 block 被算出來,或者更安全些,「等待」六個 block 被算出來

這個等待的時間遠遠長於一般日常的小額交易,例如你去超市買個咖啡交易只要三秒鐘,但等待要十分鐘

這個等待的時間遠遠短於跨國匯款的大額交易,例如你從台灣匯款到美國至少需要一天經過本地銀行+中轉行+收款行入帳,但是等待只要六十分鐘就算安全

又想到另一個問題,當初Satoshi Nakamoto 是怎麼想到 sha hash 開頭可能都是 0 ?能想到這點真是太天才了,一般常識認知 Hash 之後就是個亂數,沒想到竟然有機會找到開頭都是 0 ,這真的太神奇了!

 

2016/04/24更新

讀完了mastering-bitcoin中文版

整本沒有提出 fork chain 之後被放棄的鍊上面的交易該怎麼辦

http://zhibimo.com/read/wang-miao/mastering-bitcoin/mastering-bitcoin.pdf

Rotate Array

這題目我以前在臉書就看過了,也還不知道如何解釋

題意,給一整數陣列,陣列長度n,以及一整數k,將陣列向右移動k次,往右邊移動的那一位填補到最左邊的空位

例如

[1,2,3],1 ->[3,1,2]

[1,2,3,4,5,6,7],2 -> [6,7,1,2,3,4,5]

操作方法是先將全部reverse,再reverse前面第零個到第k個,最後reverse第k個後面到結尾

考慮進去三次reverse,時間複雜度為O(2n)

class Solution {
public:
    void rotate(int nums[], int n, int k) {
        reverse(nums, nums+n);
        reverse(nums, nums+k%n);
        reverse(nums+k%n, nums+n);
    }
};

想出解釋的方法了

向右移動 k 次,代表會有末尾 k 位跑到右邊去

所以先將整個數列反轉一次之後,把前面 k 位再反轉一次,就可以讓前面 k 位保持原本的順序

然後在將後面 n-k 位翻轉一次,讓後面剩下的位數也都保持原本的順序

這樣就完成了

Remove Element

https://oj.leetcode.com/problems/remove-element/

題意,輸入一整數陣列、陣列長度,數值A

移除該整數陣列中的數值A,並且回傳移除之後的陣列長度,長度之後的元素值無所謂,陣列中的元素順序也無所謂

例如122334,移除2,則變成133422回傳4,或者143322回傳4,第4個數字後面的值是什麼無所謂

操作方法是:遍歷每個元素,如果元素是要移除的,則往後找尋不等於要移除的元素並且找到之後進行交換

如果找到了最後一個元素都沒有找到可以交換的,那就代表整個陣列操作完成

時間複雜度是O(n+m)

class Solution {
public:
    int removeElement(int A[], int n, int elem) {
        int i=0, j=0;
        int d=0;
        bool end=false;
        while(i<n){
            if(A[i]==elem){
                if(n==1){
                    break;
                }
                j=i;
                while(1){
                    j++;
                    if(j==n){
                        end=true;
                        break;
                    }
                    if(A[j]!=elem){
                        swap(A[j],A[i]);
                        d++;
                        break;
                    }
                }
            }
            else{
                d++;
            }
            if(end){
                break;
            }
            i++;
        }
        return d;
    }
};

Remove Duplicates from Sorted Array

https://oj.leetcode.com/problems/remove-duplicates-from-sorted-array/

題目輸入一個已經從小到大排序完成的整數陣列,以及陣列長度

移除該陣列中重複的元素

操作方法是:依序讀取每一個元素,如果與前一個元素相同的話就做i++讀取下一個

如果前一個元素不同的話就做d++並且把A[i]寫到A[d]裡面去,然後做i++讀取下一個

這樣的時間複雜度是O(n)

class Solution {
public:
    int removeDuplicates(int A[], int n) {
        int i=0;
        int d=0;
        if(n==0){
            return 0;
        }
        while(i<n){
            if(i==0){
                i++;
                d++;
                continue;
            }
            if(A[i]==A[i-1]){
            }
            else{
                A[d]=A[i];
                d++;
            }
            i++;
        }
        return d;
    }
};

Same Tree

https://oj.leetcode.com/problems/same-tree/

題目輸入兩個二元樹,判斷兩個樹是否長的一模一樣

操作邏輯是,遞迴方式檢查每一個節點的左子節點和右子節點

時間複雜度是O(n)

/**
 * Definition for binary tree
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    bool isSameTree(TreeNode *p, TreeNode *q) {
        if(p==NULL && q==NULL){
            return true;
        }
        if(p==NULL || q==NULL){
            return false;
        }
        if(p->val != q->val){
            return false;
        }
        if(!isSameTree(p->left, q->left)){
            return false;
        }
        if(!isSameTree(p->right, q->right)){
            return false;
        }
        return true;
    }
};

Symmetric Tree

https://oj.leetcode.com/problems/symmetric-tree/

題目:判斷一個二元樹是否對稱

操作的邏輯是,建樹的時候遇到節點左或右子樹空缺,則補-1

每一層建立完成之後取值進行比較

這個方法的時間複雜度是O(n^2)

/**
 * Definition for binary tree
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    bool isSymmetric(TreeNode *root) {
        if(root==NULL){
            return true;
        }
        if(root->left==NULL&&root->right==NULL){
            return true;
        }
        list<int> int_list;
        queue<TreeNode*> tn_queue1;
        queue<TreeNode*> tn_queue2;
        TreeNode* tmp;
        tn_queue1.push(root);
        while(!tn_queue1.empty()){
            tmp = tn_queue1.front();
            if(tmp->left!=NULL){
                tn_queue2.push(tmp->left);
                int_list.push_back(tmp->left->val);
            }
            else{
                int_list.push_back(-1);
            }
            if(tmp->right!=NULL){
                tn_queue2.push(tmp->right);
                int_list.push_back(tmp->right->val);
            }
            else{
                int_list.push_back(-1);
            }
            tn_queue1.pop();
            if(tn_queue1.empty()){
                tn_queue1 = tn_queue2;
                tn_queue2 = queue<TreeNode*>();
                while(int_list.size()>1){
                    if(int_list.front() != int_list.back()){
                        return false;
                    }
                    int_list.pop_front();
                    int_list.pop_back();
                }
                int_list.clear();
            }
        }
        return true;
    }
};

看討論區裡面有個O(n)的作法,概念是把節點的L node, R node作為參數放入helper()

然後比較L->val, R->val

如果相同的話再比較helper(L->left, R->right) and helper(L->right, r->left)

只要有一個回傳 false 就算不對稱了