第 283 场周赛 总结

第 283 场周赛 总结

1. Excel 表中某个范围内的单元格

描述:

​ Excel 表中的一个单元格 (r, c) 会以字符串 "<col><row>" 的形式进行表示,其中:

  • <col>即单元格的列号c。用英文字母表中的字母 标识。

    • 例如,第 1 列用 'A' 表示,第 2 列用 'B' 表示,第 3 列用 'C' 表示,以此类推。
  • <row> 即单元格的行号 r 。第 r 行就用 整数 r 标识。

给你一个格式为 "<col1><row1>:<col2><row2>" 的字符串 s ,其中 <col1> 表示 c1 列,<row1> 表示 r1 行,<col2> 表示 c2 列,<row2> 表示 r2 行,并满足 r1 <= r2c1 <= c2

找出所有满足 r1 <= x <= r2c1 <= y <= c2 的单元格,并以列表形式返回。单元格应该按前面描述的格式用 字符串 表示,并以 非递减 顺序排列(先按列排,再按行排)。

示例 1:

img

输入:s = "K1:L2"
输出:["K1","K2","L1","L2"]
解释:
上图显示了列表中应该出现的单元格。
红色箭头指示单元格的出现顺序。

示例 2:

img

输入:s = "A1:F1"
输出:["A1","B1","C1","D1","E1","F1"]
解释:
上图显示了列表中应该出现的单元格。 
红色箭头指示单元格的出现顺序。

提示:

  • s.length == 5
  • 'A' <= s[0] <= s[3] <= 'Z'
  • '1' <= s[1] <= s[4] <= '9'
  • s 由大写英文字母、数字、和 ':' 组成
// 本人解法 : 找到左上角及右下角对应的 行值 列值
class Solution {
    public List<String> cellsInRange(String s) {
        List<String> ans = new ArrayList<>();
        String[] grids = s.split(":");
        // 左上角
        int i1 = grids[0].charAt(0) - 'A';
        int j1 = grids[0].charAt(1) - '0';
        // 右下角
        int i2 = grids[1].charAt(0) - 'A';
        int j2 = grids[1].charAt(1) - '0';
        // 从左上角到右下角依次遍历添加;
        for (int i = i1; i <= i2; i++) {
            StringBuffer cur = new StringBuffer();
            cur.append((char)(i + 'A'));
            for (int j = j1; j <= j2; j++) {
                cur.append((char)(j + '0'));
                ans.add(cur.toString());
                cur.deleteCharAt(1);
            }
        }
        return ans;
    }
}
// 力扣大神 @arignote(https://leetcode-cn.com/u/arignote/) 解法
// 简洁!!!
class Solution {
	public List<String> cellsInRange(String s) {
		ArrayList<String> list = new ArrayList<>();
		for (char i = s.charAt(0); i <= s.charAt(3); i++) {
			for (char j = s.charAt(1); j <= s.charAt(4); j++) {
				list.add("" + i + j);
			}
		}
		return list;
	}
}

小结: 代码不够简洁!


2. 向数组中追加 K 个整数

描述:

​ 给你一个整数数组 nums 和一个整数 k 。请你向 nums 中追加 k 出现在 nums 中的、互不相同 整数,并使结果数组的元素和 最小 。返回追加到 nums 中的 k 个整数之和。

示例 1:

输入:nums = [1,4,25,10,25], k = 2
输出:5
解释:在该解法中,向数组中追加的两个互不相同且未出现的正整数是 2 和 3 。
nums 最终元素和为 1 + 4 + 25 + 10 + 25 + 2 + 3 = 70 ,这是所有情况中的最小值。
所以追加到数组中的两个整数之和是 2 + 3 = 5 ,所以返回 5 。

示例 2:

输入:nums = [5,6], k = 6
输出:25
解释:在该解法中,向数组中追加的两个互不相同且未出现的正整数是 1 、2 、3 、4 、7 和 8 。
nums 最终元素和为 5 + 6 + 1 + 2 + 3 + 4 + 7 + 8 = 36 ,这是所有情况中的最小值。
所以追加到数组中的两个整数之和是 1 + 2 + 3 + 4 + 7 + 8 = 25 ,所以返回 25 。

提示:

  • 1 <= nums.length <= 105
  • 1 <= nums[i], k <= 109
// 本人解法(超时) 
class Solution {
    public long minimalKSum(int[] nums, int k) {
    	// 先排序
        Arrays.sort(nums);
        long ans = 0;
        // j代表已经添加的个数,n代表nums的索引
        int j = 0, n = 0;
        // 一个一个加 (费时)
        for (long m = 1; m < 100000000000001L; m++) {
            if (j == k) break;
            if (n < nums.length && (long)nums[n] == m) {
                while (n < nums.length && (long)nums[n] == m) n++;
            } else {
                ans += m;
                j++;
            }
        }
        return ans;
    }
}
// 力扣大神 @arignote(https://leetcode-cn.com/u/arignote/) 解法
class Solution {
    public long minimalKSum(int[] nums, int k) {
        // 先排序
        Arrays.sort(nums);
        // 利用等差数列公式预先计算 1 + 2 + ... + k的值
        long ans = k * (k + 1l) / 2;
        // 遍历数组,遇到比k小的,就从ans中减去该值,在加一个比k大的值!
        for (int i = 0; i < nums.length; i++) {
            if ((i== 0 || nums[i] != nums[i - 1]) && nums[i] <= k) {
                ans += ++k;
                ans -= nums[i];
            }
        }
        return ans;
    }
}

小结: 蛮力不能解决一切,要动动脑子!


3. 根据描述创建二叉树

描述:

​ 给你一个二维整数数组 descriptions ,其中 descriptions[i] = [parenti, childi, isLefti] 表示 parentichildi二叉树 中的 父节点,二叉树中各节点的值 互不相同 。此外:

  • 如果 isLefti == 1 ,那么 childi 就是 parenti 的左子节点。
  • 如果 isLefti == 0 ,那么 childi 就是 parenti 的右子节点。

请你根据 descriptions 的描述来构造二叉树并返回其 根节点 。测试用例会保证可以构造出 有效 的二叉树。

示例 1:

img

输入:descriptions = [[20,15,1],[20,17,0],[50,20,1],[50,80,0],[80,19,1]]
输出:[50,20,80,15,17,19]
解释:根节点是值为 50 的节点,因为它没有父节点。
结果二叉树如上图所示。

示例 2:

img

输入:descriptions = [[1,2,1],[2,3,0],[3,4,1]]
输出:[1,2,null,null,3,4]
解释:根节点是值为 1 的节点,因为它没有父节点。 
结果二叉树如上图所示。 

提示:

  • 1 <= descriptions.length <= 104
  • descriptions[i].length == 3
  • 1 <= parenti, childi <= 105
  • 0 <= isLefti <= 1
  • descriptions 所描述的二叉树是一棵有效二叉树
// 本人解法: 根据题意很好挂每个节点,但是具体返回哪个结点困惑了我很久。
// 最后选择用一个map表,记录每个节点的父节点,如果最后某个节点的父节点是自己,则说明它是头结点!
class Solution {
    public TreeNode createBinaryTree(int[][] descriptions) {
        // map1 存储不同的 节点
        Map<Integer, TreeNode> map1 = new HashMap<>();
        // parent 存储 key的父节点value
        Map<Integer, Integer> parent = new HashMap<>();
      
        // 建立不同的结点;初始化parent就是自己
        for (int i = 0; i < descriptions.length; i++) {
            TreeNode cur = new TreeNode(descriptions[i][0]);
            TreeNode child = new TreeNode(descriptions[i][1]);
            if (!map1.containsKey(cur)) {
                map1.put(descriptions[i][0], cur);
                parent.put(descriptions[i][0], descriptions[i][0]);
            }
            if (!map1.containsKey(child)) {
                map1.put(descriptions[i][1], child);
                parent.put(descriptions[i][1], descriptions[i][1]);
            }
        }
        
        // 挂节点
        for (int i = 0; i < descriptions.length; i++) {
            if (descriptions[i][2] == 1) map1.get(descriptions[i][0]).left = map1.get(descriptions[i][1]);
            else map1.get(descriptions[i][0]).right = map1.get(descriptions[i][1]);
            parent.put(descriptions[i][1], descriptions[i][0]);
        }
        
        // 从任一节点开始,一直向上找自己的父节点,直到找到父节点为自己(即 头结点)
        int x = descriptions[0][0];
        while (x != parent.get(x)) {
            x = parent.get(x);
        }
        return map1.get(x);
        
    }
}
// 力扣大神 @arignote(https://leetcode-cn.com/u/arignote/) 解法
class Solution {
	public TreeNode createBinaryTree(int[][] descriptions) {
		HashMap<Integer, TreeNode> map = new HashMap<>();
        // 同本人方法的挂节点
		for (int[] description : descriptions) {
			if (description[2] == 0) {
                // computeIfAbsent() 方法对 hashMap 中指定 key 的值进行重新计算,如果不存在这个 key,则添加到 hashMap 中。
				map.computeIfAbsent(description[0], t -> new TreeNode(description[0])).right = map
						.computeIfAbsent(description[1], t -> new TreeNode(description[1]));
			} else {
				map.computeIfAbsent(description[0], t -> new TreeNode(description[0])).left = map
						.computeIfAbsent(description[1], t -> new TreeNode(description[1]));
			}
		}
        // 思路不同之处!绝!!!
        // 遍历descriptions,从map中删除作为子节点的key,即只剩最后一个头结点!
		for (int[] description : descriptions) {
			map.remove(description[1]);
		}
		return map.values().iterator().next();
	}
}

小结: 多看最优解找思路!


4. 替换数组中的非互质数

描述:

给你一个整数数组 nums 。请你对数组执行下述操作:

  1. nums 中找出 任意 两个 相邻非互质 数。
  2. 如果不存在这样的数,终止 这一过程。
  3. 否则,删除这两个数,并 替换 为它们的 最小公倍数(Least Common Multiple,LCM)。
  4. 只要还能找出两个相邻的非互质数就继续 重复 这一过程。

返回修改后得到的 最终 数组。可以证明的是,以 任意 顺序替换相邻的非互质数都可以得到相同的结果。

生成的测试用例可以保证最终数组中的值 小于或者等于 108

两个数字 xy 满足 非互质数 的条件是:GCD(x, y) > 1 ,其中 GCD(x, y)xy最大公约数

示例 1 :

输入:nums = [6,4,3,2,7,6,2]
输出:[12,7,6]
解释:
- (6, 4) 是一组非互质数,且 LCM(6, 4) = 12 。得到 nums = [12,3,2,7,6,2] 。
- (12, 3) 是一组非互质数,且 LCM(12, 3) = 12 。得到 nums = [12,2,7,6,2] 。
- (12, 2) 是一组非互质数,且 LCM(12, 2) = 12 。得到 nums = [12,7,6,2] 。
- (6, 2) 是一组非互质数,且 LCM(6, 2) = 6 。得到 nums = [12,7,6] 。
现在,nums 中不存在相邻的非互质数。
因此,修改后得到的最终数组是 [12,7,6] 。
注意,存在其他方法可以获得相同的最终数组。

示例 2 :

输入:nums = [2,2,1,1,3,3,3]
输出:[2,1,1,3]
解释:
- (3, 3) 是一组非互质数,且 LCM(3, 3) = 3 。得到 nums = [2,2,1,1,3,3] 。
- (3, 3) 是一组非互质数,且 LCM(3, 3) = 3 。得到 nums = [2,2,1,1,3] 。
- (2, 2) 是一组非互质数,且 LCM(2, 2) = 2 。得到 nums = [2,1,1,3] 。
现在,nums 中不存在相邻的非互质数。 
因此,修改后得到的最终数组是 [2,1,1,3] 。 
注意,存在其他方法可以获得相同的最终数组。

提示:

  • 1 <= nums.length <= 105
  • 1 <= nums[i] <= 105
  • 生成的测试用例可以保证最终数组中的值 小于或者等于 108
// 力扣大神 @arignote(https://leetcode-cn.com/u/arignote/) 解法

// java.math.BigInteger 用来表示任意大小的整数
import java.math.BigInteger;

class Solution {
	public List<Integer> replaceNonCoprimes(int[] nums) {
		ArrayList<Integer> list = new ArrayList<>();
		for (int num : nums) {
            // BigInteger里的 a.gcd(b)方法 求a和b的最大公约数
			while (!list.isEmpty()
					&& BigInteger.valueOf(num).gcd(BigInteger.valueOf(list.get(list.size() - 1))).intValue() > 1) {
				num *= list.get(list.size() - 1)
						/ BigInteger.valueOf(num).gcd(BigInteger.valueOf(list.remove(list.size() - 1))).intValue();
			}
			list.add(num);
		}
		return list;
	}
}

小结: 对编程语言的各种内置函数的熟悉任重道远!

本人Leetcode主页—spade,欢迎学习交流

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值