数组转树

�定义一个 convert 函数,将以下数组转换为树结构。

  1. interface IArrayItem {
  2. id: number
  3. name: string
  4. parentId: number
  5. }
  6. interface ITreeNode {
  7. id: number
  8. name: string
  9. children?: ITreeNode[]
  10. }
  11. function convert(arr: IArrayItem[]): ITreeNode | null {
  12. // 用于 id 和 treeNode 的映射
  13. const idToTreeNode: Map<number, ITreeNode> = new Map()
  14. let root = null
  15. arr.forEach(item => {
  16. const { id, name, parentId } = item
  17. // 定义 tree node 并加入 map
  18. const treeNode: ITreeNode = { id, name }
  19. idToTreeNode.set(id, treeNode)
  20. // 找到 parentNode 并加入到它的 children
  21. const parentNode = idToTreeNode.get(parentId)
  22. if (parentNode) {
  23. if (parentNode.children == null) parentNode.children = []
  24. parentNode.children.push(treeNode)
  25. }
  26. // 找到根节点
  27. if (parentId === 0) root = treeNode
  28. })
  29. return root
  30. }
  31. const arr = [
  32. { id: 1, name: '部门A', parentId: 0 }, // 0 代表顶级节点,无父节点
  33. { id: 2, name: '部门B', parentId: 1 },
  34. { id: 3, name: '部门C', parentId: 1 },
  35. { id: 4, name: '部门D', parentId: 2 },
  36. { id: 5, name: '部门E', parentId: 2 },
  37. { id: 6, name: '部门F', parentId: 3 },
  38. ]
  39. const tree = convert(arr)
  40. console.info(tree)

树转数组

思路

  • 遍历树节点(广度优先)
  • 讲树节点转为Array Item,push到数组
  • 根据父子关系,找到Array Item的parentld ```typescript interface IArrayItem { id: number name: string parentId: number }

interface ITreeNode { id: number name: string children?: ITreeNode[] }

function convert1(root: ITreeNode): IArrayItem[] { // Map const nodeToParent: Map = new Map()

  1. const arr: IArrayItem[] = []
  2. // 广度优先遍历,queue
  3. const queue: ITreeNode[] = []
  4. queue.unshift(root) // 根节点 入队
  5. while (queue.length > 0) {
  6. const curNode = queue.pop() // 出队
  7. if (curNode == null) break
  8. const { id, name, children = [] } = curNode
  9. // 创建数组 item 并 push
  10. const parentNode = nodeToParent.get(curNode)
  11. const parentId = parentNode?.id || 0
  12. const item = { id, name, parentId }
  13. arr.push(item)
  14. // 子节点入队
  15. children.forEach(child => {
  16. // 映射 parent
  17. nodeToParent.set(child, curNode)
  18. // 入队
  19. queue.unshift(child)
  20. })
  21. }
  22. return arr

}

const obj = { id: 1, name: ‘部门A’, children: [ { id: 2, name: ‘部门B’, children: [ { id: 4, name: ‘部门D’ }, { id: 5, name: ‘部门E’ } ] }, { id: 3, name: ‘部门C’, children: [ { id: 6, name: ‘部门F’ } ] } ] } const arr1 = convert1(obj) console.info(arr1)

  1. <a name="kG8VU"></a>
  2. ## [两数之和](https://leetcode-cn.com/problems/two-sum/)
  3. - 使用 map
  4. ```javascript
  5. var twoSum = function(nums, target) {
  6. // 暴力遍历
  7. // for(let i = 0, len = nums.length; i<len-1; i++) {
  8. // for(let j = i+1; j < len; j++) {
  9. // if(nums[i] + nums[j] == target){
  10. // return [i, j]
  11. // }
  12. // }
  13. // }
  14. // return null;
  15. let map = new Map();
  16. for(let i = 0, len = nums.length; i < len; i++) {
  17. if(map.has(target-nums[i])) {
  18. return [map.get(target-nums[i]), i];
  19. } else {
  20. map.set(nums[i], i)
  21. }
  22. }
  23. return null
  24. };

三数之和

var threeSum = function(nums) {
    let ans = [];
    const len = nums.length;
    if(nums == null || len < 3) return ans;
    nums.sort((a, b) => a - b); // 排序
    for (let i = 0; i < len ; i++) {
        // 因为数组已经排序完,如果当前数字大于0,则三数之和一定大于0,所以结束循环
        if(nums[i] > 0) break; 
        if(i > 0 && nums[i] == nums[i-1]) continue; // 去重
        let L = i+1;
        let R = len-1;
        while(L < R){
            const sum = nums[i] + nums[L] + nums[R];
            if(sum == 0){
                ans.push([nums[i],nums[L],nums[R]]);
                while (L<R && nums[L] == nums[L+1]) L++; // 去重
                while (L<R && nums[R] == nums[R-1]) R--; // 去重
                L++;
                R--;
            }
            else if (sum < 0) L++;
            else if (sum > 0) R--;
        }
    }        
    return ans;
};

最长回文子串

  • 如果子串只有一个字母,那么该子串就是最短的回文字符串;
  • 对于一个子串而言,如果它是回文串,并且长度大于 2,那么将它首尾的两个字母去除之后,它仍然是个回文串。例如:对于回文字符串“ababa”,我们把首尾两个字母去除后,剩下的子串一定也是回文串。

    暴力破解

    image.png
    image.png

    中心扩散法

    https://leetcode-cn.com/problems/longest-palindromic-substring/solution/by-smooth-b-5rej/
    https://leetcode-cn.com/problems/longest-palindromic-substring/solution/zui-chang-hui-wen-zi-chuan-by-leetcode-solution/

    var longestPalindrome = function(s) {
      let left, right, nowMax, len = s.length, maxLength = 0, maxStart;
      for(let i = 0; i < len; i++) {
          left = i - 1;
          right = i + 1;
          nowMax = 1; // 当前区间最大长度重置为 1
          // 从中心 i 出发,往左找到第一个不同的,即开始找可能会不满足题意的回文子串,并准备判断
          while(left >= 0 && s[left] === s[i]) {
              left--;
              nowMax++;
          }
          // 从中心 i 出发,往右找到第一个不同的,即开始找可能会不满足题意的回文子串,并准备判断
          while(right < len && s[right] === s[i]) {
              right++;
              nowMax++;
          }
          // 开始左右指针各往外遍历,寻找到第一个不符合回文串的位置
          while(left >= 0 && right < len && s[left] === s[right]) {
              left--;
              right++;
              nowMax += 2;
          }
          // 遍历结束,看看此时子串是否最大
          if(nowMax > maxLength) {
              maxLength = nowMax;
              maxStart = left;
          }
      }
    
      return s.substring(maxStart + 1, maxStart + 1 + maxLength);
    };
    

动态规划

https://leetcode-cn.com/problems/longest-palindromic-substring/solution/shi-pin-tu-jie-dong-tai-gui-hua-zui-chang-hui-wen-/

解题思路:

  • 已知单个字母就是一个回文子串,那么我们可以从两个字符开始判断,如:“ababc”,我们依次比较 “ab”、“ba”、“ab”、“bc”,判断是否存在回文字符串,并记录每个子串的结果(什么结果?每个子串开始下标和结束下标位置对应的结果——是否为回文字符串:true/false。怎么记录?用二维数组),接着开始依次比较三个字符串”abc“、”bab“、”abc“ 并记录结果,最后依次比较四个字符串 ”abab“、”babc“并记录结果。这期间每次比较完子串后,如果当前子串是回文字符串时,会去判断当前子串的长度是否大于当前记录的最大子串长度,如果大于的话就会覆盖最大值。

    1、获取不同长度的子串

    ```javascript function longestPalindrome(str) { const len = str.length; if (len < 2) {
      return str;
    
    } for (let childStrLen = 2; childStrLen <= len; childStrLen++) {
      for (let l = 0; l < len; l++) {
          let r = childStrLen + l - 1;
          // 一旦子串的结束位置等于/超过字符串长度,就终止本轮比较
          if (r >= len) {
              break;
          }
          console.log("childStr", str.substring(l, r + 1));
      }
    
    } }

console.log(‘result’, longestPalindrome(“babadab”));

// childStr ba // childStr ab // childStr ba // childStr ad // childStr da // childStr ab // childStr bab // childStr aba // childStr bad // childStr ada // childStr dab // childStr baba // childStr abad // childStr bada // childStr adab // childStr babad // childStr abada // childStr badab // childStr babada // childStr abadab // childStr babadab


<a name="DUCn4"></a>
#### 2、创建二维数组并赋默认值
```javascript
function longestPalindrome(str) {
    const len = str.length;
    if (len < 2) {
        return str;
    }

    // 创建二维数组并赋默认值
    let twoDimensionalArr = Array.from(new Array(len), () => new Array(len).fill(false));
    // 单个字母是回文字符串,所以直接设置为 true
    twoDimensionalArr.forEach((it, i) => twoDimensionalArr[i][i] = true);

    for (let childStrLen = 2; childStrLen <= len; childStrLen++) {
        for (let l = 0; l < len; l++) {
            let r = childStrLen + l - 1;
            // 一旦子串的结束位置等于/超过字符串长度,就终止本轮比较
            if (r >= len) {
                break;
            }
        }
    }
}

console.log('result', longestPalindrome("babadab"));

// 我们只需要看对角线右上方的值就行,因为 l 的不可能会比 r 大,所以不会用到对角线下方的值
// [
//     [true, false, false, false, false, false, false],
//     [false, true, false, false, false, false, false],
//     [false, false, true, false, false, false, false],
//     [false, false, false, true, false, false, false],
//     [false, false, false, false, true, false, false],
//     [false, false, false, false, false, true, false],
//     [false, false, false, false, false, false, true]
// ]

3、开始比较

function longestPalindrome(str) {
    const len = str.length;
    if (len < 2) {
        return str;
    }
    let maxLen = 1;
    let begin = 0;
    // 创建二维数组并赋默认值
    let twoDimensionalArr = Array.from(new Array(len), () => new Array(len).fill(false));
    // 单个字母是回文字符串,所以直接设置为 true
    twoDimensionalArr.forEach((it, i) => twoDimensionalArr[i][i] = true);
    for (let childStrLen = 2; childStrLen <= len; childStrLen++) {
          for (let l = 0; l < len; l++) {
            let r = childStrLen + l - 1;
            // 一旦子串的结束位置等于/超过字符串长度,就终止本轮比较
            if (r >= len) {
                break;
            }
            // 如果首尾字符不相等,那么当前子串肯定不是回文字符串
            if (str[l] !== str[r]) {
                twoDimensionalArr[l][r] = false;
            } else {
                // 特殊情况:如果当前子串长度为 2 并且首尾字符相等时,那么当前子串就是回文字符串,不需要去掉首尾两个字符,再判断中间内容是否为回文字符串
                if (childStrLen === 2) {
                    twoDimensionalArr[l][r] = true;
                } else {
                    // 如果首尾字符相等,那就去掉首尾两个字符,继续判断子串中间的内容是否为回文字符串
                    twoDimensionalArr[l][r] = twoDimensionalArr[l + 1][r - 1];
                }
            }
            if (twoDimensionalArr[l][r] && childStrLen > maxLen) {
                maxLen = childStrLen;
                begin = l;
            }
        }
    }
    // console.log(twoDimensionalArr);

    return str.substring(begin, begin + maxLen);
}

console.log('result', longestPalindrome("babadab"));

// 默认值
// [
//     [true, false, false, false, false, false, false],
//     [false, true, false, false, false, false, false],
//     [false, false, true, false, false, false, false],
//     [false, false, false, true, false, false, false],
//     [false, false, false, false, true, false, false],
//     [false, false, false, false, false, true, false],
//     [false, false, false, false, false, false, true]
// ]

// 最终的值
// [
//     [true, false, true, false, false, false, false], 
//     [false, true, false, true, false, false, false], 
//     [false, false, true, false, false, false, true], 
//     [false, false, false, true, false, true, false],
//     [false, false, false, false, true, false, false], 
//     [false, false, false, false, false, true, false], 
//     [false, false, false, false, false, false, true]
// ]

???疑问???

//  这里用 map 代替了二维数组,这个代码在 LeetCode 可以运行成功,但是一提交就会超时,目前不明所以
function longestPalindrome(str) {
    const len = str.length;
    if (len < 2) {
        return str;
    }
    let maxLen = 1;
    let begin = 0;
    let map = new Map();
    for (let i = 0; i < len; i++) {
        map.set(i + '-' + i, true)
    }
    for (let childStrLen = 2; childStrLen <= len; childStrLen++) {
        for (let l = 0; l < len; l++) {
            let r = childStrLen + l - 1;
            // 一旦子串的结束位置等于/超过字符串长度,就终止本轮比较
            if (r >= len) {
                break;
            }
            const key = l + '-' + r;
            if (str[l] !== str[r]) {
                map.set(key, false)
            } else {
                if (childStrLen === 2) {
                    map.set(key, true)
                } else {
                    const key2 = (l + 1) + '-' + (r - 1);
                    const val = map.get(key2);
                    map.set(key, val)
                }
            }
            if (map.get(key) && childStrLen > maxLen) {
                maxLen = childStrLen;
                begin = l;
            }
        }
    }
    console.log(map);
    return str.substring(begin, begin + maxLen);
}

console.log('result', longestPalindrome("babadab"));