leetcode刷题记录(25)-简单

这篇博客记录了LeetCode的五道题目解题思路,包括转置矩阵、二进制间距、叶子相似的树、模拟行走机器人以及链表的中间节点。解题方法涉及行列转换、指针法、深度优先遍历等技巧。
摘要由CSDN通过智能技术生成

1.转置矩阵

题目:

给定一个矩阵 A, 返回 A 的转置矩阵。

矩阵的转置是指将矩阵的主对角线翻转,交换矩阵的行索引与列索引。

思路:行列下标转换就行

/**
 * @param {number[][]} A
 * @return {number[][]}
 */
var transpose = function(A) {
  const h = A.length;
  const w = A[0].length;
  const res = new Array(w).fill("").map(() => new Array(h));
  for (let i = 0; i < h; i++) {
    for (let j = 0; j < w ; j++) {
      res[j][i] = A[i][j];
    }
  }
  return res;
};

2.二进制矩阵

题目:

给定一个正整数 N,找到并返回 N 的二进制表示中两个相邻 1 之间的最长距离。 

如果没有两个相邻的 1,返回 0 。

思路:指针法。用一个变量记录上一次遇到1时的下标,每次比较即可

/**
 * @param {number} N
 * @return {number}
 */
var binaryGap = function(N) {
  const s = N.toString(2);
  let length = s.length;
  let max = 0;
  let left = 0;
  for (let i = 0; i < length; i++) {
    if (s[i] == "1") {
      max = max < i - left ? i - left : max;
      left = i;
    }
  }
  return max;
};

也可用字符串'1'分割字符串,去掉首尾的成员,取剩下的成员中长度最大的那个

/**
 * @param {number} N
 * @return {number}
 */
var binaryGap = function(N) {
  const s = N.toString(2);
 const words=s.split('1')
 words.pop()
 words.shift()
  return words.length?Math.max(...words.map(s=>s.length+1)):0;
};

3.叶子相似的树

题目:

请考虑一颗二叉树上所有的叶子,这些叶子的值按从左到右的顺序排列形成一个 叶值序列 。

举个例子,如上图所示,给定一颗叶值序列为 (6, 7, 4, 9, 8) 的树。

如果有两颗二叉树的叶值序列是相同,那么我们就认为它们是 叶相似 的。

如果给定的两个头结点分别为 root1 和 root2 的树是叶相似的,则返回 true;否则返回 false 。

思路:先用深度优先遍历,找出所有的叶节点,、然后两棵树生成叶节点连接的字符串,比较即可

/**
 * Definition for a binary tree node.
 * function TreeNode(val) {
 *     this.val = val;
 *     this.left = this.right = null;
 * }
 */
/**
 * @param {TreeNode} root1
 * @param {TreeNode} root2
 * @return {boolean}
 */
var leafSimilar = function (root1, root2) {
    const rec = (t) => {
        if (!t) return ''
        if (!t.left && !t.right) return `${t.val}-`

        return rec(t.left)+rec(t.right)
    }
    return rec(root1) === rec(root2)
};

或者用数组,先生成一棵树的节点,然后另一颗树去比较,优点是不需要遍历第二棵树所有的节点


/**
 * Definition for a binary tree node.
 * function TreeNode(val) {
 *     this.val = val;
 *     this.left = this.right = null;
 * }
 */
/**
 * @param {TreeNode} root1
 * @param {TreeNode} root2
 * @return {boolean}
 */
var leafSimilar = function(root1, root2) {
 const leaf = [];
  let flag = true;
  const search = (root, type) => {
    if (!flag) return;
    if (!root) {
      return;
    }
    if (!root.left && !root.right) {
      if (type) {
        leaf.push(root.val);
      } else {
        flag = leaf.shift() === root.val;
      }
      return;
    }
      search(root.left, type);
      search(root.right, type);
  };
  search(root1, true);
  search(root2, false);
  return flag
};

4.模拟行走的机器人

题目:

机器人在一个无限大小的网格上行走,从点 (0, 0) 处开始出发,面向北方。该机器人可以接收以下三种类型的命令:

-2:向左转 90 度
-1:向右转 90 度
1 <= x <= 9:向前移动 x 个单位长度
在网格上有一些格子被视为障碍物。

第 i 个障碍物位于网格点  (obstacles[i][0], obstacles[i][1])

机器人无法走到障碍物上,它将会停留在障碍物的前一个网格方块上,但仍然可以继续该路线的其余部分。

返回从原点到机器人所有经过的路径点(坐标为整数)的最大欧式距离的平方。

思路:

由题意可知,初始化机器人位置为原点(0,0)
初始化坐标系
dx = [0,1,0,-1]
dy = [1,0,-1,0]
其实就是坐标系点从北部方向顺时针方向存放点坐标的方向向量数组
dx和dy一一对应一个坐标点
机器人行走方向
(-2):左转,O->W,Wx = (Ox+3)%4
(-1):右转,O->E,Wx = (Ox+1)%4
解释
方向只有东西南北四个方向,所以无论怎么走,都不会超出方向向量数组里的取值范围
因此通过取模来循环取对应数组的位置
(x): 机器人不转弯并向前走X个格子
一步一步走,从1开始遍历
判断下一步是否有障碍物
有,继续走
无,进入下一轮
解题技巧
存储障碍物为hash表,提升程序性能

/**
 * @param {number[]} commands
 * @param {number[][]} obstacles
 * @return {number}
 */
var robotSim = function(commands, obstacles) {
   var dx = [0,1,0,-1];
    var dy = [1,0,-1,0];
    var di = 0;
    var endX = 0;
    var endY = 0;
    var result = 0;
    var hashObstacle = {};
    for(var r = 0;r<obstacles.length;r++){
        hashObstacle[obstacles[r][0]+'-'+obstacles[r][1]] = true;
    }
    for(var s = 0;s<commands.length;s++){
        if(commands[s] == -2){
            di = (di+3)%4;
        }else if(commands[s] == -1){
            di = (di+1)%4;
        }else{
            // 每次走一步
            for(var z = 1;z <= commands[s];z++){
                var nextX = endX + dx[di];
                var nextY = endY + dy[di];
                // 判断下一步是否为障碍物
                if(hashObstacle[nextX+'-'+nextY]){
                    break;
                }
                endX = nextX;
                endY = nextY;
                result = Math.max(result,endX*endX+endY*endY);
            }
        }
    }
    return result;

};

5.链表的中间节点

题目:

给定一个带有头结点 head 的非空单链表,返回链表的中间结点。

如果有两个中间结点,则返回第二个中间结点。

思路:快慢指针或者用数组都行

/**
 * Definition for singly-linked list.
 * function ListNode(val) {
 *     this.val = val;
 *     this.next = null;
 * }
 */
/**
 * @param {ListNode} head
 * @return {ListNode}
 */
var middleNode = function(head) {
  const list = [];
  while (head) {
    list.push(head);
    head=head.next
  }
  return list[~~(list.length / 2)]|| null;
};
/**
 * Definition for singly-linked list.
 * function ListNode(val) {
 *     this.val = val;
 *     this.next = null;
 * }
 */
/**
 * @param {ListNode} head
 * @return {ListNode}
 */
var middleNode = function(head) {
  let fast = head;
  let slow = head;
  while (fast && fast.next) {
    fast = fast.next.next;
    slow = slow.next;
  }
  return slow;
};

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值