阿里巴巴访谈:用最小空格打印句子

时间:2018-05-10 07:00:17

标签: javascript algorithm dictionary

我看到了这个面试问题并且放手了。我被困。面试问题是:

  

给定一个字符串

var s = "ilikealibaba";
     

和字典

var d = ["i", "like", "ali", "liba", "baba", "alibaba"];
     

尝试给出带有最小空间的s

     

输出可能是

     
      
  1. 我喜欢阿里巴巴(2个车位)
  2.   
  3. 我喜欢阿里巴巴(3个空格)
  4.         

    但选择1号

我有一些代码,但卡在打印中。 如果你有更好的方法来解决这个问题,请告诉我。

function isStartSub(part, s) {
  var condi = s.startsWith(part);
  return condi;
}

function getRestStr(part, s) {
  var len = part.length;
  var len1 = s.length;
  var out = s.substring(len, len1);
  return out;
}

function recPrint(arr) {
    if(arr.length == 0) {
        return '';
    } else {
        var str = arr.pop();
        return str + recPrint(arr);
    }

}

// NOTE: have trouble to print
// Or if you have better ways to do this interview question, please let me know
function myPrint(arr) {
    return recPrint(arr);
}

function getMinArr(arr) {
    var min = Number.MAX_SAFE_INTEGER;
    var index = 0;
    for(var i=0; i<arr.length; i++) {
        var sub = arr[i];
        if(sub.length < min) {
            min = sub.length;
            index = i;
        } else {

        }   
    }

    return arr[index];  
}

function rec(s, d, buf) {
    // Base
    if(s.length == 0) {
        return;
    } else {

    } 

    for(var i=0; i<d.length; i++) {
        var subBuf = [];

        // baba
        var part = d[i];
        var condi = isStartSub(part, s);

        if(condi) {
            // rest string  
      var restStr = getRestStr(part, s);
      rec(restStr, d, subBuf);
            subBuf.unshift(part);
            buf.unshift(subBuf);
        } else {

        }       
    } // end loop

}

function myfunc(s, d) {
    var buf = [];
    rec(s, d, buf);

    console.log('-- test --');
    console.dir(buf, {depth:null});

    return myPrint(buf);    
}


// Output will be
// 1. i like alibaba (with 2 spaces)
// 2. i like ali baba (with 3 spaces)
// we pick no.1, as it needs less spaces
var s = "ilikealibaba";
var d = ["i", "like", "ali", "liba", "baba", "alibaba"];
var out = myfunc(s, d);
console.log(out);

基本上,我的输出是,不知道如何打印....

[ [ 'i', [ 'like', [ 'alibaba' ], [ 'ali', [ 'baba' ] ] ] ] ]

4 个答案:

答案 0 :(得分:3)

此问题最适合动态编程方法。子问题是“创建s前缀的最佳方法是什么”。然后,对于给定前缀s,我们会考虑与前缀末尾匹配的所有单词,并使用前面前缀的结果选择最佳单词。

这是一个实现:

var s = "ilikealibaba";
var arr = ["i", "like", "ali", "liba", "baba", "alibaba"];

var dp = []; // dp[i] is the optimal solution for s.substring(0, i)
dp.push("");

for (var i = 1; i <= s.length; i++) {
    var best = null; // the best way so far for s.substring(0, i)

    for (var j = 0; j < arr.length; j++) {
        var word = arr[j];
        // consider all words that appear at the end of the prefix
        if (!s.substring(0, i).endsWith(word))
            continue;

        if (word.length == i) {
            best = word; // using single word is optimal
            break;
        }

        var prev = dp[i - word.length];
        if (prev === null)
            continue; // s.substring(i - word.length) can't be made at all

        if (best === null || prev.length + word.length + 1 < best.length)
            best = prev + " " + word;
    }
    dp.push(best);
}

console.log(dp[s.length]);

答案 1 :(得分:1)

当您被要求找到最短的答案时,Breadth-First Search可能是一个可能的解决方案。或者您可以查看A* Search

以下是A *的工作示例(因为它比BFS少做了:)),基本上只是从维基百科文章中复制而来。所有&#34;将字符串转换为图形&#34; magick发生在getNeighbors函数

https://jsfiddle.net/yLeps4v5/4/

var str = 'ilikealibaba'
var dictionary = ['i', 'like', 'ali', 'baba', 'alibaba']

var START = -1
var FINISH = str.length - 1

// Returns all the positions in the string that we can "jump" to from position i
function getNeighbors(i) {
    const matchingWords = dictionary.filter(word => str.slice(i + 1, i + 1 + word.length) == word)
    return matchingWords.map(word => i + word.length)
}

function aStar(start, goal) {
    // The set of nodes already evaluated
    const closedSet = {};

    // The set of currently discovered nodes that are not evaluated yet.
    // Initially, only the start node is known.
    const openSet = [start];

    // For each node, which node it can most efficiently be reached from.
    // If a node can be reached from many nodes, cameFrom will eventually contain the
    // most efficient previous step.
    var cameFrom = {};

    // For each node, the cost of getting from the start node to that node.
    const gScore = dictionary.reduce((acc, word) => { acc[word] = Infinity; return acc }, {})

    // The cost of going from start to start is zero.
    gScore[start] = 0

    while (openSet.length > 0) {
        var current = openSet.shift()
        if (current == goal) {
            return reconstruct_path(cameFrom, current)
        }

        closedSet[current] = true;

        getNeighbors(current).forEach(neighbor => {
            if (closedSet[neighbor]) {
                return      // Ignore the neighbor which is already evaluated.
            }

            if (openSet.indexOf(neighbor) == -1) {  // Discover a new node
                openSet.push(neighbor)
            }

            // The distance from start to a neighbor
            var tentative_gScore = gScore[current] + 1
            if (tentative_gScore >= gScore[neighbor]) {
                return      // This is not a better path.
            }

            // This path is the best until now. Record it!
            cameFrom[neighbor] = current
            gScore[neighbor] = tentative_gScore
        })
    }

    throw new Error('path not found')
}

function reconstruct_path(cameFrom, current) {
    var answer = [];
    while (cameFrom[current] || cameFrom[current] == 0) {
        answer.push(str.slice(cameFrom[current] + 1, current + 1))
        current = cameFrom[current];
    }
    return answer.reverse()
}

console.log(aStar(START, FINISH));

答案 2 :(得分:0)

您可以通过检查起始字符串并然后渲染结果来收集字符串的所有可能组合。

如果多个结果具有最小长度,则会获得所有结果。

对于包含相同基本字符串的字符串(例如#cat fun_a.py def fun_a(abcd): print '%s - %s'%(abcd, efgh) if __name__ == "__main__": pass #python Python 2.7.5 (default, Oct 11 2015, 17:47:16) [GCC 4.8.3 20140911 (Red Hat 4.8.3-9)] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> from fun_a import * >>> efgh = 'test2' >>> fun_a('test1') Traceback (most recent call last): File "<stdin>", line 1, in <module> File "fun_a.py", line 2, in fun_a print '%s - %s'%(abcd, efgh) NameError: global name 'efgh' is not defined 'abcabc')的极值,它可能不起作用。在这种情况下,我建议使用最短的字符串并通过迭代更新任何部分结果,以便找到更长的字符串并在可能的情况下进行替换。

&#13;
&#13;
'abc'
&#13;
&#13;
&#13;

答案 3 :(得分:0)

使用trie数据结构

  1. 构建基于字典数据的trie数据结构
  2. 在句子中搜索所有可能的切片并构建解决方案树
  3. 深入遍历解决方案树并对最终组合进行排序
  4. const sentence = 'ilikealibaba';
    const words = ['i', 'like', 'ali', 'liba', 'baba', 'alibaba',];
    
    class TrieNode {
        constructor() { }
        set(a) {
            this[a] = this[a] || new TrieNode();
            return this[a];
        }
        search(word, marks, depth = 1) {
            word = Array.isArray(word) ? word : word.split('');
            const a = word.shift();
            if (this[a]) {
                if (this[a]._) {
                    marks.push(depth);
                }
                this[a].search(word, marks, depth + 1);
            } else {
                return 0;
            }
        }
    }
    
    TrieNode.createTree = words => {
        const root = new TrieNode();
        words.forEach(word => {
            let currentNode = root;
            for (let i = 0; i < word.length; i++) {
                currentNode = currentNode.set(word[i]);
            }
            currentNode.set('_');
        });
        return root;
    };
    
    const t = TrieNode.createTree(words);
    
    function searchSentence(sentence) {
        const marks = [];
        t.search(sentence, marks);
        const ret = {};
        marks.map(mark => {
            ret[mark] = searchSentence(sentence.slice(mark));
        });
        return ret;
    }
    
    const solutionTree = searchSentence(sentence);
    
    function deepTraverse(tree, sentence, targetLen = sentence.length) {
        const stack = [];
        const sum = () => stack.reduce((acc, mark) => acc + mark, 0);
        const ret = [];
        (function traverse(tree) {
            const keys = Object.keys(tree);
            keys.forEach(key => {
                stack.push(+key);
                if (sum() === targetLen) {
                    const result = [];
                    let tempStr = sentence;
                    stack.forEach(mark => {
                        result.push(tempStr.slice(0, mark));
                        tempStr = tempStr.slice(mark);
                    });
                    ret.push(result);
                }
                if(tree[key]) {
                    traverse(tree[key]);
                }
                stack.pop();
            });
        })(tree);
        return ret;
    }
    
    const solutions = deepTraverse(solutionTree, sentence);
    
    solutions.sort((s1, s2) => s1.length - s2.length).forEach((s, i) => {
        console.log(`${i + 1}. ${s.join(' ')} (${s.length - 1} spaces)`);
    });
    console.log('pick no.1');