Categories
木有技术

LeetCode 23. Merge k Sorted Lists

https://leetcode.com/problems/merge-k-sorted-lists/description/
Use max heap, the time complexity is O( log(k) * N )

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* mergeKLists(vector<ListNode*>& lists) {
        if (lists.empty())
            return nullptr;
        auto comparor = [](ListNode* lhs, ListNode* rhs) {
            return lhs->val > rhs->val;
        };
        priority_queue<ListNode*, vector<ListNode*>, decltype(comparor)> pri_queue(comparor);
        // perpare queue with K items
        for(auto& list : lists)
        {
            if (list != nullptr)
                pri_queue.push(list);
        }
        ListNode* head = new ListNode(-1);
        ListNode* prev = head;
        ListNode* current = nullptr;
        while (!pri_queue.empty())
        {
            current = pri_queue.top();
            prev->next = current;
            ListNode* next = current->next;
            pri_queue.pop();
            if (next != nullptr)
                pri_queue.push(next);
            prev = current;
        }
        return head->next;
    }
};

 

Categories
木有技术

LeetCode 222. Count Complete Tree Nodes

https://leetcode.com/problems/count-complete-tree-nodes/description/
简单的二分法分治,探测(子)树的左右侧是否相等即可。
(下面代码没实现)想要更快的话,其实自从第一次算出左侧的深度后,后面的左测深度直接可以通过减法求出,不用再去探测一次了。

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    int countLevel(TreeNode* root, bool to_left) {
        int count = 0;
        while (root != nullptr)
        {
            count++;
            root = to_left ? root->left : root->right;
        }
        return count;
    }
    int countNodes(TreeNode* root) {
        if (root == nullptr)
            return 0;
        int lvl_left = countLevel(root, true);
        int lvl_right = countLevel(root, false);
        if (lvl_left == lvl_right)
        {
            // finally
            return (1 << lvl_left) - 1; // 2^n - 1
        }
        else
        {
            return 1 + countNodes(root->left) + countNodes(root->right);
        }
    }
};

 

Categories
工作

No core will be dumped when calling exit() in a signal handler

The customized abnormal signal handler (e.g. SIGSEGV handler) will function abnormally if we call exit() inside the handler: the program will exit “as normal” however it did had some severe memory issue.
See code snippet below, try to run with / without “X” argument.

/* exit example */
#include <stdio.h>      /* printf, fopen */
#include <stdlib.h>     /* exit, EXIT_FAILURE */
#include <signal.h>     /* signal */
#include <string.h>
bool disable_exit = false;
void InitiateAbnormalShutdown()
{
    printf("ABNORMAL SHUTDOWN!!!\n");
    if (!disable_exit)
        exit(EXIT_FAILURE);
}
void AbnormalSignalHandler(int signo)
{
    signal(signo, SIG_DFL);
    InitiateAbnormalShutdown();
    raise(signo);
}
bool give_me_an_error()
{
    int* test = new int;
    *test = 500;
    delete test;
    test = NULL;
    *test = 900;
    if (*test > 500)
    {
        return false;
    }
    return true;
}
int main(int argc, char *argv[])
{
    if (argc > 1)
    {
        printf("arg == %s\n", argv[1]);
        if (strcmp(argv[1], "X") == 0)
        {
            printf("disable exit on abnormal handler...\n");
            disable_exit = true;
        }
    }
    signal(SIGSEGV, AbnormalSignalHandler);
    give_me_an_error();
    return 0;
}

Output:

bowei.he:/sandbox/bowei.he/temp$ ./sigf
ABNORMAL SHUTDOWN!!!
bowei.he:/sandbox/bowei.he/temp$ ./sigf X
arg == X
disable exit on abnormal handler...
ABNORMAL SHUTDOWN!!!
Segmentation fault (core dumped)

 
 

Categories
不学无术

LeetCode 76. Minimum Window Substring

76. Minimum Window Substring
思路:
构造一个哈希表结构统计我们的需求,也就是字符串t中每个字符的数量,方便起见如果有需求则哈希表的对应值-1。另外存储一下当前解的起始位置START以及最优解的位置。
扫描字符串s,在位置s[i]时如果能够满足需求(即哈希表中没有负值),则从START开始清除无用的字符直至无法满足需求位置。比如需求是A:1, B:2,START开始的字符是DEFBAB,则清除DEF。清除完成后更新START值并跟当前已知的最优解比较,更新最优解。
啰嗦一句,似乎相当一部分substring类型的题目都能用hash table + two pointers的方式解决。

class Solution {
public:
    static string minWindow(string s, string t) {
        int count_map[128] = {0};
        set<char> req_set;
        int start_index = -1, min_start_index = 0;
        int min_end_index = INT_MAX;
        for (const char& c : t)
        {
            count_map[c] --;
            req_set.insert(c);
        }
        for (int i = 0; i < s.size(); ++i)
        {
            const char c = s[i];
            count_map[c] ++;
            bool require_sufficed = true;
            for (const char& c : req_set)
            {
                if (count_map[c] < 0)
                {
                    require_sufficed = false;
                    break;
                }
            }
            if (!require_sufficed) continue;
            // clear left
            for (int j = start_index + 1; j <= i; ++j)
            {
                if (--count_map[s[j]] < 0)
                {
                    start_index = j;
                    break;
                }
                start_index = j;
            }
            if (i - start_index < min_end_index - min_start_index)
            {
                min_start_index = start_index;
                min_end_index = i;
            }
        }
        if (min_end_index == INT_MAX)
            return "";
        else
            return s.substr(min_start_index, min_end_index - min_start_index + 1);
    }
};

 

Categories
不学无术

LeetCode 432. All O`one Data Structure

几万年没做LeetCode的题了,更新一下。
https://leetcode.com/problems/all-oone-data-structure/description/
这道题的思路是用一个双向链表(list)来存储一个以value排序的数据结构,使用哈希表(unordered_map)来存储key到链表iterator的映射:

需要注意特殊处理value=1的Node的情况。
代码写得比较毛糙,但是确实是O(1)的复杂度,如果要优化的话map的插入可以用emplace()之类的。
注意:除了value=1的节点,其余节点的keys为空的时候要把该节点删除掉,否则getMaxKey()和getMinKey()就需要O(n)的遍历操作了。

struct KvNode
{
    unordered_set<string> keys;
    int value = 1;
};
class AllOne {
private:
    list<KvNode> value_key;     // arranged by val in ascending order
    using list_it_t = list<KvNode>::iterator;
    unordered_map<string, list_it_t> val_map;
    list_it_t init_node;    //node with value one
public:
    /** Initialize your data structure here. */
    AllOne() {
        value_key.push_back(KvNode());
        init_node = value_key.begin();
    }
    /** Inserts a new key <Key> with value 1. Or increments an existing key by 1. */
    void inc(const string& key) {
        if (val_map.find(key) == val_map.end())
        {
            // `create' new node with value 1
            init_node->keys.insert(key);
            val_map[key] = init_node;
        }
        else
        {
            // find existing node
            auto node_it = val_map[key];
            node_it->keys.erase(key);   //remove from current bulk
            auto next_it = std::next(node_it, 1);
            if (next_it == value_key.end() ||
                 next_it->value != node_it->value + 1)
            {
                // no valid valued bulk, create one
                KvNode node;
                node.keys.insert(key);
                node.value = node_it->value + 1;
                val_map[key] = value_key.insert(next_it, node);
            }
            else
            {
                next_it->keys.insert(key);
                val_map[key] = next_it;
            }
            if (node_it->keys.empty() && node_it->value != 1)
            {
                // remove node_it
                value_key.erase(node_it);
            }
        }
    }
    /** Decrements an existing key by 1. If Key's value is 1, remove it from the data structure. */
    void dec(string key) {
        auto it_val_map = val_map.find(key);
        if (it_val_map == val_map.end())
        {
            // key does not exist
            return;
        }
        else if (it_val_map->second->value == 1)
        {
            auto node_it = it_val_map->second;
            node_it->keys.erase(key);
            if (node_it->keys.empty() && node_it->value != 1)
            {
                value_key.erase(node_it);
            }
            val_map.erase(it_val_map);
        }
        else
        {
            auto node_it = it_val_map->second;
            auto prev_it = std::prev(node_it, 1);
            node_it->keys.erase(key);
            if (prev_it->value != node_it->value - 1)
            {
                // create one
                KvNode node;
                node.keys.insert(key);
                node.value = node_it->value - 1;
                val_map[key] = value_key.insert(node_it, node);
            }
            else
            {
                prev_it->keys.insert(key);
                val_map[key] = prev_it;
            }
            if (node_it->keys.empty() && node_it->value != 1)
            {
                value_key.erase(node_it);
            }
        }
    }
    /** Returns one of the keys with maximal value. */
    string getMaxKey() {
        auto it_max = std::prev(value_key.end(), 1);
        if (!it_max->keys.empty())
            return *(it_max->keys.begin());
        else
            return "";
    }
    /** Returns one of the keys with Minimal value. */
    string getMinKey() {
        auto it_min = value_key.begin();
        if (it_min->value == 1 && it_min->keys.empty())
            ++it_min;
        if (it_min != value_key.end() && !it_min->keys.empty())
            return *(it_min->keys.begin());
        else
            return "";
    }
};
/**
 * Your AllOne object will be instantiated and called as such:
 * AllOne obj = new AllOne();
 * obj.inc(key);
 * obj.dec(key);
 * string param_3 = obj.getMaxKey();
 * string param_4 = obj.getMinKey();
 */

 
 
 

Categories
木有技术

Linux Performance Observability Tools


Source(Crash Dump Analysis): http://d3s.mff.cuni.cz/teaching/crash_dump_analysis/slides/08-linux.pdf

Categories
未分类

Boost up your ShadowSocks server with BBR

在尝试各种SS优化之后,我发现唯一对我服务器有用的是Google的BBR——一个TCP拥塞控制算法。
具体的一些评价,可以参考知乎的问题《Linux Kernel 4.9 中的 BBR 算法与之前的 TCP 拥塞控制相比有什么优势?
Ubuntu下的简单部署:

  1. 确认一下你的内核版本
    uname -r

    如果返回的是>=4.9的版本,那么直接跳到第4

  2. 下载内核安装包。最新版的内核可以去http://kernel.ubuntu.com/~kernel-ppa/mainline/ 查看,这边下载的是4.13版
    wget http://kernel.ubuntu.com/~kernel-ppa/mainline/v4.13/linux-headers-4.13.0-041300_4.13.0-041300.201709031731_all.deb
    wget http://kernel.ubuntu.com/~kernel-ppa/mainline/v4.13/linux-headers-4.13.0-041300-generic_4.13.0-041300.201709031731_amd64.deb
    wget http://kernel.ubuntu.com/~kernel-ppa/mainline/v4.13/linux-image-4.13.0-041300-generic_4.13.0-041300.201709031731_amd64.deb
  3. 安装新的内核(确保你有sudo权限)
    dpkg -i linux-headers-*.deb
    dpkg -i linux-image-*.deb

    然后删除系统里原来的内核,首先确认一下删除的版本,运行这个命令找到旧版本的内核

    dpkg -l | grep linux-image

    删掉

    apt-get remove <旧内核映像文件> --purge

    别忘了更新grub,不然引导不来了

    update-grub
    reboot #重启
  4. 配置sysctl启用BBR
    编辑/etc/sysctl.conf , 在文件末尾加上下面两行

    net.core.default_qdisc=fq
    net.ipv4.tcp_congestion_control=bbr

    然后键入sysctl -p 令配置生效

 

 
参考:

  1. https://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git/commit/?id=0f8782ea14974ce992618b55f0c041ef43ed0b78
  2. https://www.zxavier.com/shadowsocks%E4%BC%98%E5%8C%96.html
Categories
生活琐碎

Spring 2018

春节到了,好久没有更新博客。
最近都在忙着工作的事情,总算是要步入正轨了,新的一年还有很多东西要搞,希望自己能尽全力而为。
最开心的事情是两天前跟妹子求了个婚,花销虽然有点大,不过还是值得的。杭州柏悦的服务还是不错的,虽然最后弄得一团糟被收了清洁费,也是很值得。发现当一切都安排妥当之后,会有一种莫名的淡定,哈哈。
狗年即将发生很多更奇妙的事情, 只能说要自己加油再加油。在老家书柜里看到了巴金的《家》《春》《秋》三部曲,感觉可以带一本去上海,都是1970年代出版的老书,那时候一本书才一块多钱。
今年的目标是:

  • 工作上,要拿到涨薪和对得起自己的bonus
  • 学习上,年初把统计和机器学习再学习一下,有深深的预感不久的将来会用到大把
  • 生活上,争取去更多的地方玩

 

Categories
不学无术

Bayes Network: D-Separation

某一变量的已知/未知会影响其他变量的相互独立性。
来自Udacity的CS217课

Categories
不学无术

Problem Solving (CS271)

Problem solving works when:

  • The domain must be fully observable: we must be able to see what initial state we start out with;
    全局都是可见的
  • The domain must be known: we have to know the set of available actions to us;
    知晓可进行的操作
  • The domain must be discrete: there must be a finite number of actions to be chose from;
    可进行的操作是有限多的
  • The domain must be deterministic: we have to know the result of taking an action;
    进行一项操作带来的结果是可知的