Categories
不学无术

LeetCode 146. LRU Cache

思路

双向链表+哈希表实现,要明白STL里的<map>是红黑树实现的,亲测速度不够,要用真.哈希表:<unordered_map>
可能有人要问,为啥不用单向链表?我的理解是为了删除元素的时候不用从头搜索。
当然,针对这道题是可以用单向链表的,即“删除”最无用节点的时候,对链表不作处理,而只是从哈希表里把值删掉。反正在搜索的时候也是直接查的哈希表。副作用是这个链表会越来越长。
另外,不想自己实现双向链表的话,可以用<list>

代码

struct LinkedNode{
    int key;
    LinkedNode* next;
    LinkedNode* prev;
    LinkedNode(int _key = -1){
        key = _key;
        next = NULL;
        prev = NULL;
    }
};
class LRUCache{
private:
    LinkedNode* pHeader;
    LinkedNode* pEnd;
    unordered_map<int, int> keyValueMap;
    int cap;
public:
    LRUCache(int capacity) {
        cap = capacity;
        pHeader = new LinkedNode(); //dummy node
        pEnd = new LinkedNode();
        pHeader->next = pEnd;
        pEnd->prev = pHeader;
    }
    void refreshQueue(int key){
        LinkedNode* pNode = pHeader;
        while(pNode->next != NULL){
            if(pNode->next->key == key)
                break;
            pNode = pNode->next;
        }
        //Move pNode->next to head
        LinkedNode* pPrevNode = pNode;
        LinkedNode* pHitNode = pNode->next;
        LinkedNode* pNextNode = pHitNode->next;
        pPrevNode->next = pNextNode;
        pNextNode->prev = pPrevNode;
        pHeader->next->prev = pHitNode;
        pHitNode->prev = pHeader;
        pHitNode->next = pHeader->next;
        pHeader->next = pHitNode;
    }
    int removeLast(){
        //Remove the last item and return its key
        LinkedNode* pToRemove = pEnd->prev;
        int key = pToRemove->key;
        LinkedNode* pPrev = pToRemove->prev;
        pPrev->next = pEnd;
        pEnd->prev = pPrev;
        delete pToRemove;
        return key;
    }
    int get(int key) {
        if(keyValueMap.count(key) > 0){
            //Change priority queue
            refreshQueue(key);
            //Get value
            return keyValueMap[key];
        } else {
            return -1;
        }
    }
    void insert(int key){
        LinkedNode* pNext = pHeader->next;
        LinkedNode* pNewNode = new LinkedNode(key);
        pNewNode->next = pNext;
        pNewNode->prev = pHeader;
        pHeader->next = pNewNode;
        pNext->prev = pNewNode;
    }
    void set(int key, int value) {
        if(keyValueMap.count(key)){
            keyValueMap[key] = value; //set key
            //Refresh queue
            refreshQueue(key);
        } else {
            if(keyValueMap.size() == cap){
                int oldKey = removeLast();
                keyValueMap.erase(oldKey);
            }
            keyValueMap[key] = value;
            insert(key);
        }
    }
};

 

Categories
不学无术

LeetCode 139. Word Break

Given a string s and a dictionary of words dict, determine if s can be segmented into a space-separated sequence of one or more dictionary words.
For example, given
s = "leetcode",
dict = ["leet", "code"].
Return true because "leetcode" can be segmented as "leet code".

思路

字符串处理的一个题目,首先想到的办法就是穷举:从头开始找N-letter word,查一下在不在字典里呗。但是纯穷举的话显然就会超时,因为这个问题可以分解成下面的子问题,即给定字符串s及起始位置start,寻找s[start…end]能不能够被拆分。这个子问题在暴力搜索的时候很容易被重复,所以得找个东西记录一下状态,碰到相同的子问题就不用再去查字典了。
所以,他是个动态规划的题。

代码

bool wordBreakSub(const string& s, unordered_set<string>& wordDict, int startPos, int* memory)
{
    if(memory[startPos] != -1)
        return memory[startPos]!= 0;
    string subStr;
    bool canBreak = false;
    for(int len=1; len <= s.size() - startPos; len++)
    {
        subStr = s.substr(startPos, len);
        if(wordDict.count(subStr) > 0) {
            if (startPos + len == s.size()) {
                memory[startPos] = 1;
                return true;
            }
            canBreak = wordBreakSub(s, wordDict, startPos + len, memory);
        }
        if(canBreak)
            break;
    }
    memory[startPos] = canBreak ? 1 : 0;
    return canBreak;
}
bool wordBreak(string s, unordered_set<string>& wordDict)
{
    int* memory = new int[s.size()];
    for(int i=0; i<s.size(); i++)
        memory[i] = -1; //-1:untest; 0-false; 1-true
    return wordBreakSub(s, wordDict, 0, memory);
}

 

Categories
不学无术

LeetCode 116. Populating Next Right Pointers in Each Node

思路

发现是一个树的遍历的题目,而且题目限制的比较死,是个满二叉树,这样处理的时候就避免了比较烦人的跨树指针的情况。比如下面这种建立4->5的指针:

    1
  2   3
4    5  6

第一时间想到的解法是弄个工作队列,然后一层一层遍历下去就行了,这个解法的空间复杂度是O(n),不符合题目要求。后来再一想,其实既然上一层已经把下一层的next指针建立好了,就不用再从工作队列里去“回忆”了,只要在每一行的开头记住下一行在哪里就行,这样只要O(1)空间复杂度。
另外是如何设置next指针,一共有两个情况:

  1. node自己的左孩子和右孩子连起来
  2. node的右孩子与node右侧节点它的左孩子连起来

代码

O(n)空间复杂度方法

/**
 * Definition for binary tree with next pointer.
 * struct TreeLinkNode {
 *  int val;
 *  TreeLinkNode *left, *right, *next;
 *  TreeLinkNode(int x) : val(x), left(NULL), right(NULL), next(NULL) {}
 * };
 */
class Solution {
public:
    void connect(TreeLinkNode *root) {
        queue<TreeLinkNode*> workingQ;
        if(root == NULL)
            return;
        workingQ.push(root);
        while(!workingQ.empty())
        {
            TreeLinkNode* node = workingQ.front();
            workingQ.pop();
            if(node->left == NULL || node->right == NULL)
                continue;   //Leaf node
            node->left->next = node->right; //Inner connection
            if(node->next != NULL)
                node->right->next = node->next->left; //Outter connection
            workingQ.push(node->left);
            workingQ.push(node->right);
        }
    }
};

O(1)空间复杂度方法

class Solution {
public:
    void connect(TreeLinkNode *root) {
        TreeLinkNode* nextRowPtr = root;
        TreeLinkNode* node = root;
        bool atRowStart = true;
        while(nextRowPtr != NULL)
        {
            if(node->left == NULL || node->right == NULL)
                break;   //Leaf node
            if(atRowStart)
            {
                atRowStart = false;
                nextRowPtr = node->left;
            }
            node->left->next = node->right; //Inner connection
            if(node->next != NULL)
            {
                node->right->next = node->next->left; //Outter connection
                node = node->next;
            }
            else
            {
                node = nextRowPtr;
                atRowStart = true;  //End of current row
            }
        }
    }
};

 

Categories
不学无术 木有技术

LeetCode 385. Mini Parser

思路

一开始还以为又回到了编译原理,想到了状态转换图啊之类的。后来发现这个题目没有这么变态,要考虑的是个栈的问题。
为什么会想到栈呢?因为看到了括号,因为括号结束的时候我们要把某个部分的内容添到更大的括号里头去。
我的处理方式是:

  • 构造一个工作栈,一开始是空的
  •  碰到数字
    • 生成一个只包含数字的NestedInteger
      • 如果工作栈空,那么字符串就是个纯数字,直接返回
      • 如果工作栈非空,那么这个字符串就要加到当前工作栈顶端的元素后面(考虑情况[35,345]这种)
  • 碰到'[‘
    • 新建一个空的NestedInteger(至于里面填什么,不是这里要考虑的事儿)
    • 把它压入栈
  • 碰到’]’
    • 取出当前栈顶元素formerTop
    • 判断栈是否空了
      • 非空,则formerTop要加到当前栈顶的后面
      • 空,可以返回了
  • 碰到’,’
    • 其实没什么用,往前挪动吧

这个步骤还能再精简一下的,判断栈是否空,是否返回的部分是重复了

代码

/**
 * // This is the interface that allows for creating nested lists.
 * // You should not implement it, or speculate about its implementation
 * class NestedInteger {
 *   public:
 *     // Constructor initializes an empty nested list.
 *     NestedInteger();
 *
 *     // Constructor initializes a single integer.
 *     NestedInteger(int value);
 *
 *     // Return true if this NestedInteger holds a single integer, rather than a nested list.
 *     bool isInteger() const;
 *
 *     // Return the single integer that this NestedInteger holds, if it holds a single integer
 *     // The result is undefined if this NestedInteger holds a nested list
 *     int getInteger() const;
 *
 *     // Set this NestedInteger to hold a single integer.
 *     void setInteger(int value);
 *
 *     // Set this NestedInteger to hold a nested list and adds a nested integer to it.
 *     void add(const NestedInteger &ni);
 *
 *     // Return the nested list that this NestedInteger holds, if it holds a nested list
 *     // The result is undefined if this NestedInteger holds a single integer
 *     const vector<NestedInteger> &getList() const;
 * };
 */
class Solution {
private:
    stack<NestedInteger*> workingStack;
public:
    int readIntVal(const string& s, int& pos)
    {
        // pos will be set to the end index of current integer
        int value = 0;
        bool neg = false;
        if(s[pos] == '-'){
            neg = true;
            pos++;
        }
        while(pos < s.size() &&
                (s[pos] >= '0' && s[pos] <= '9'))
        {
            value *= 10;
            value += (s[pos] - '0');
            pos++;
        }
        pos--;
        return neg? -value : value;
    }
    NestedInteger deserialize(string s) {
        int pos = 0;
        while(pos < s.size())
        {
            char c = s[pos];
            if(c == '-' || (c >= '0' && c <= '9'))
            {
                NestedInteger* digitNI = new NestedInteger(readIntVal(s, pos)); //Integer containing NestedInteger
                if(workingStack.empty())
                {
                    //Should return
                    return *digitNI;
                }
                else
                {
                    //Append to existing NI
                    NestedInteger* currNI = workingStack.top();
                    currNI->add(*digitNI);
                    pos++;
                }
            }
            else if(c == ',')
            {
                pos++;
            }
            else if(c == '[')
            {
                //Create an NI and push to working stack
                NestedInteger* ni = new NestedInteger();
                workingStack.push(ni);
                pos++;
            }
            else if(c == ']')
            {
                //pop workingStack and append former-top item to current top
                NestedInteger* formerTop = workingStack.top();
                workingStack.pop();
                if(workingStack.empty())
                    return *formerTop;
                else
                {
                    //Append
                    NestedInteger* currTop = workingStack.top();
                    currTop->add(*formerTop);
                    pos++;
                }
            }
        }
        //Shouldn't be here!
        return NestedInteger();
    }
};

题目

Given a nested list of integers represented as a string, implement a parser to deserialize it.
Each element is either an integer, or a list — whose elements may also be integers or other lists.
Note: You may assume that the string is well-formed:

  • String is non-empty.
  • String does not contain white spaces.
  • String contains only digits 0-9, [, - ,, ].

Example 1:

Given s = "324",
You should return a NestedInteger object which contains a single integer 324.

Example 2:

Given s = "[123,[456,[789]]]",
Return a NestedInteger object containing a nested list with 2 elements:
1. An integer containing value 123.
2. A nested list containing two elements:
    i.  An integer containing value 456.
    ii. A nested list with one element:
         a. An integer containing value 789.
Categories
木有技术

LeetCode 14. Longest Common Prefix

Write a function to find the longest common prefix string amongst an array of strings.

分析

这个题目直接扫一遍就行了,复杂度是O(min(strlen)),strlen是字符串的长度

代码

class Solution {
public:
    string longestCommonPrefix(vector<string>& strs) {
        if(strs.size() == 0)
            return "";
        else if(strs.size() == 1)
            return strs[0];
        int currPos = 0;
        bool shouldStop = false;
        while(!shouldStop){
            char c;
            for(int row=0; row < strs.size(); row++){
                if(strs[row].size() == currPos){
                    shouldStop = true;//Meet the end of some string
                    break;
                }
                if(row == 0){
                    c = strs[row][currPos];
                } else {
                    if(strs[row][currPos] != c){
                        shouldStop = true;
                        break;
                    }
                }
            }
            if(!shouldStop)
                currPos++;
        }
        return strs[0].substr(0, currPos);
    }
};

 

Categories
不学无术

LeetCode 343. Integer Break

Given a positive integer n, break it into the sum of at least two positive integers and maximize the product of those integers. Return the maximum product you can get.
For example, given n = 2, return 1 (2 = 1 + 1); given n = 10, return 36 (10 = 3 + 3 + 4).
Note: You may assume that n is not less than 2 and not larger than 58.

思路 O(n^2)

注:这题还有O(n)解决的方法,我提交的方法是O(n^2)的。
有点像动态规划的题,上一个数的状态经过乘法可以作为下个数的备选(要与下个数比较)。
假设result[i]存了当前能加到i的最好结果值;
第一遍,从1开始往后加(反正最大的n也就58),1+1=2,则result[2]中就是1*1=1,1+2=3=>result[3]=1*2=2;result[4]=3
第二遍,从2开始往后加,a[3]=2,a[4]=2*2(原始值为3,这里更新为4),…

第五遍,从5开始往后加,但之前算的过程中,result[5]的结果已经被更新成了6,这个数比5大,因此×的时候,被乘数是6而不是5;
以此类推…

思路 O(logn)

需要一点数学思维,详见https://discuss.leetcode.com/topic/42991/o-log-n-time-solution-with-explanation

代码

public class Solution {
    public int max(int x, int y){
        return x>y ? x : y;
    }
    public int integerBreak(int n) {
        int[] result = new int[59]; //0 to 58
        result[1] = 1;  //dummy
        for(int i=1; i<=n-1; i++)
        {
            for(int j=1; j<=n-i; j++)
            {
                int temp = result[i];
                if(result[i] < i)
                    temp = i;
                result[i+j]=max(result[i+j], temp * j);
            }
        }
        return result[n];
    }
}

 

Categories
木有技术

LeetCode 62. Unique Paths

原题:https://leetcode.com/problems/unique-paths/
robot is located at the top-left corner of a m x n grid (marked ‘Start’ in the diagram below).
The robot can only move either down or right at any point in time. The robot is trying to reach the bottom-right corner of the grid (marked ‘Finish’ in the diagram below).
How many possible unique paths are there?

Above is a 3 x 7 grid. How many possible unique paths are there?
Note: m and n will be at most 100.

思路

这是个经典的题目,反正就是动态规划的思路?说是动态规划,其实就是下一个状态怎么来的问题。此处的下一状态就是一个格子solution[m][n]他的结果是怎么来的问题,由于限定只能往右或者往下走,所以这个格子的走法无非是 从(m,n-1)和(m-1,n)走过来两种,只要把这两个状态的结果相加就是当前总的走法了。

解法

复杂度应该是O(m*n),做的时候在左侧和上侧加了个0边便于计算

public class Solution {
    public int uniquePaths(int m, int n) {
        int solutions[][] = new int[m+1][n+1];
        solutions[1][1]=1;
        for(int i=1; i<=m; i++){
            for(int j=1; j<=n; j++){
                if(i==1 && j==1)
                    continue;
                solutions[i][j] = solutions[i][j-1] + solutions[i-1][j];    // Comes from left, or upper side
            }
        }
        return solutions[m][n];
    }
}

 

Categories
木有技术

LeetCode 278. First Bad Version

做点简单的题目练练手,最近天天在写Scope脚本,都快忘记怎么写其他代码了。
吐槽一下垃圾长城宽带,上LeetCode都要自己开代理,不然根本加载不了

You are a product manager and currently leading a team to develop a new product. Unfortunately, the latest version of your product fails the quality check. Since each version is developed based on the previous version, all the versions after a bad version are also bad.
Suppose you have n versions [1, 2, ..., n] and you want to find out the first bad one, which causes all the following ones to be bad.
You are given an API bool isBadVersion(version) which will return whether version is bad. Implement a function to find the first bad version. You should minimize the number of calls to the API.

分析

这其实就是个变种的二分查找,只要注意找到一个bad version的时候,往前多看一个版本就能决定是否要继续二分下去了。

代码

// Forward declaration of isBadVersion API.
bool isBadVersion(int version);
class Solution {
public:
    int firstBadVersion(int n) {
        int low = 1;
        int high = n;
        while(true){
            int mid = low + (high - low)/2;
            if(isBadVersion(mid)){
                //Look for previous cases
                bool isBad = isBadVersion(mid);
                if(isBad){
                    if(mid == 1)
                        return mid;
                    if(!isBadVersion(mid-1))
                        return mid;
                    high = mid - 1;
                } else {
                    low = mid + 1;
                }
            } else {
                low = mid + 1;
            }
        }
    }
};

 

Categories
iDairy

长城宽带迅雷下BT缓慢临时解决办法

在北京实习,当上了伪北漂。因为只租三个月左右,权衡各种就选了长城宽带,这个价格算下来其实跟去年双自己家11买的电信100M差不多,不过质量么就呵呵哒了。360元(号称)70M,3个月。长宽国内访问还好,一到国际出口就坑比了,Github上面Push东西都Push不上去,国内的估计是做了缓存的,常见资源访问很快,不是热点的资源就得加载卡一点,下载差不多3MB/s吧,就是电信20M的水平。
一句话:搭个国内代理(比如SS)先下载几分钟,然后切回到长城宽带继续下载。
吐槽结束,然后最近找电影看,发现BT很容易就下不动。之前有在哪里看到过说长城宽带封迅雷的,抱着试试看的心理试了试别的办法。由于自己有个阿里云ECS的账号,所以在上面搭了个sh@d0ws0cks服务器。众所周知这货是翻q用的,但是可以开全局代理啊。然后我试了一下一模一样的一个电影种子,原来无法访问离线下载的毛病解决了,速度瞬间上去。稳定一阵后把SS切回原样照样能下载。
我深深怀疑是封端口之类的了,一开始类似建立连接的步骤没办法进行就一直卡着,后面大概p2p端口多了也封不完?纯属胡猜,反正管用

Categories
木有技术

Spring MVC POST FormData乱码问题(不使用web.xml)

在使用jQuery ajax一个FormData的时候(我要同时传文件和数据,所以用了FormData),发现上传的表单数据里,中文都是乱码。查到的结果就是说Servlet在没有读到ContentType的时候,会默认使用ISO-8859-1编码。具体原因可以参考《Spring MVC的Post请求参数中文乱码的原因&处理
Web.xml上添加Filter有个等效的Java写法,我的项目里没有web.xml配置文件:)
其实就是在extends AbstractAnnotationConfigDispatcherServletInitializer的时候override一个方法

@Override
    protected Filter[] getServletFilters() {
        CharacterEncodingFilter encodingFilter = new CharacterEncodingFilter();
        encodingFilter.setEncoding("UTF-8");
        return new Filter[]{encodingFilter};
    }

然后就好了,很方便