2023-03-16:给定一个由 0 和 1 组成的数组 arr ,将数组分成 3 个非空的部分,
使得所有这些部分表示相同的二进制值。
如果可以做到,请返回任何 [i, j],其中 i+1 < j,这样一来,
arr[0], arr[1], …, arr[i] 为第一部分,
arr[i + 1], arr[i + 2], …, arr[j - 1] 为第二部分,
arr[j], arr[j + 1], …, arr[arr.length - 1] 为第三部分,
这三个部分所表示的二进制值相等,
如果无法做到,就返回 [-1, -1]。
注意,在考虑每个部分所表示的二进制时,应当将其看作一个整体,
例如,[1,1,0] 表示十进制中的 6,而不会是 3。此外,前导零也是被允许的,
所以 [0,1,1] 和 [1,1] 表示相同的值。
输入:arr = [1,0,1,0,1],
输出:[0,3]。
输入:arr = [1,1,0,0,1],
输出:[0,2]。

答案2023-03-16:

给定一个由 0 和 1 组成的数组 arr,需要将其分成三个非空部分,使得每个部分中 1 的数量相等。如果无法做到,则返回 [-1, -1]。

输入:由 0 和 1 组成的数组 arr,长度为 n(1 ≤ n ≤ 3×10^4),且只包含数字 0 和 1。

输出:长度为 2 的数组,表示能够将 arr 分成三个部分时第一个和第二个部分的结束位置(下标从 0 开始)。如果无法做到则返回 [-1, -1]。

解法思路:

首先统计整个数组中 1 的数量 ones,如果 ones 不能被 3 整除,则说明无法分成三个相等的部分,直接返回 [-1, -1]。

如果 ones 等于 0,则整个数组都是 0,可以返回 [0, n-1]。

接着需要找到第一个、第二个和第三个部分的起始位置。根据题意,第一个部分和第二个部分的 1 的数量应该是 ones/3,因此可以先计算出目标值 part = ones/3,然后从左到右遍历整个数组,在找到第一个和第二个部分之后,继续遍历找到第三个部分的起始位置。

接下来检查第三个部分是否也等于目标值 part。如果是,则返回 [end1, end2],否则返回 [-1, -1]。

代码实现:

fn main() {
let arr1 = vec![0, 0, 0, 0, 0];
println!("{:?}", three_equal_parts(arr1)); // [0, 4] let arr2 = vec![1, 0, 1, 0, 1, 0];
println!("{:?}", three_equal_parts(arr2)); // [1, 4] let arr3 = vec![1, 0, 1, 0, 1];
println!("{:?}", three_equal_parts(arr3)); // [0, 3] let arr4 = vec![1, 0, 1, 1, 1];
println!("{:?}", three_equal_parts(arr4)); // [-1, -1] let arr5 = vec![0, 1, 0, 1, 0, 1, 0, 1, 0, 1];
println!("{:?}", three_equal_parts(arr5)); // [-1, -1] let arr6 = vec![1, 1, 0, 1, 1, 0, 1, 1];
println!("{:?}", three_equal_parts(arr6)); // [1, 5]
} pub fn three_equal_parts(arr: Vec<i32>) -> Vec<i32> {
let ones = arr.iter().filter(|&num| *num == 1).count(); // 统计数组中 1 的个数
if ones % 3 != 0 {
// 如果无法分成三个相等的部分,则返回 [-1, -1]
return vec![-1, -1];
}
let n = arr.len();
if ones == 0 {
// 如果整个数组都是 0,则返回 [0, n-1]
return vec![0, n as i32 - 1];
}
let part = ones / 3; // 计算每个子数组中 1 的数量
let mut start1 = -1; // 第一个子数组的起始位置
let mut start2 = -1; // 第二个子数组的起始位置
let mut start3 = -1; // 第三个子数组的起始位置
let mut cnt = 0; // 当前已经遇到的 1 的数量
for i in 0..n {
if arr[i] == 1 {
cnt += 1;
if start1 == -1 && cnt == 1 {
start1 = i as i32; // 找到第一个子数组的起始位置
}
if start2 == -1 && cnt == part + 1 {
start2 = i as i32; // 找到第二个子数组的起始位置
}
if start3 == -1 && cnt == 2 * part + 1 {
start3 = i as i32; // 找到第三个子数组的起始位置
}
}
}
while start3 < n as i32 {
if arr[start1 as usize] != arr[start2 as usize]
|| arr[start1 as usize] != arr[start3 as usize]
{
return vec![-1, -1]; // 如果找到的三个子数组不相等,则返回 [-1, -1]
}
start1 += 1;
start2 += 1;
start3 += 1;
}
vec![start1 - 1, start2] // 返回第一个和第二个子数组的结束位置
}

算法分析:

该算法的时间复杂度为 O(n),其中 n 是输入数组的长度,因为需要遍历整个数组一次。空间复杂度为 O(1),只需要常量级别的额外空间存储一些变量。该算法的优点是简单易懂,缺点是可能会超时,比如当输入数组中有很多连续的 1 时。可以通过进一步优化算法来提高效率。

测试结果:

1.测试用例:[0,0,0,0,0],预期输出:[0, 4]。

assert_eq!(three_equal_parts(vec![0,0,0,0,0]), vec![0, 4]);

2.测试用例:[1, 0, 1, 0, 1, 0],预期输出:[1, 4]。

assert_eq!(three_equal_parts(vec![1, 0, 1, 0, 1, 0]), vec![1, 4]);

3.测试用例:[1, 0, 1, 0, 1],预期输出:[0, 3]。

assert_eq!(three_equal_parts(vec![1, 0, 1, 0, 1]), vec![0, 3]);

4.测试用例:[1, 0, 1, 1, 1],预期输出:[-1, -1]。

assert_eq!(three_equal_parts(vec![1, 0, 1, 1, 1]), vec![-1, -1]);

5.测试用例:[0, 1, 0, 1, 0, 1, 0, 1, 0, 1],预期输出:[-1, -1]。

assert_eq!(three_equal_parts(vec![0, 1, 0, 1, 0, 1, 0, 1, 0, 1]), vec![-1, -1]);

6.测试用例:[1, 1, 0, 1, 1, 0, 1, 1],预期输出:[1, 5]。

assert_eq!(three_equal_parts(vec![1, 1, 0, 1, 1, 0, 1, 1]), vec![1, 5]);

总结和展望:

本文介绍了一种简单的算法,可以解决给定一个由 0 和 1 组成的数组 arr,需将其分成三个非空部分,使得每个部分中 1 的数量相等的问题。该算法的核心思路是计算目标值 target_val,并在遍历整个数组两次的过程中找到第一个和第二个部分的结束位置 i 和 j。该算法的时间复杂度为 O(n),空间复杂度为 O(1)。

有一些情况下该算法可能会超时,比如当输入数组中有很多连续的 1 时。可以通过进一步优化算法来提高效率。例如,可以使用双指针来记录第一个和第二个部分的结束位置,从而减少遍历数组的次数。另外,可以使用位运算来加速计算当前部分的二进制数值。

2023-03-16:给定一个由 0 和 1 组成的数组 arr ,将数组分成 3 个非空的部分, 使得所有这些部分表示相同的二进制值。 如果可以做到,请返回任何 [i, j],其中 i+1 < j的更多相关文章

  1. 2018/03/16 每日一个Linux命令 之 rm

    最痛快的指令,没有之一. 一次永久删除,恢复很麻烦. 我会告诉你我第一次上服务器的时候删除了项目代码?(还好我提前备份了一下) -- rm [-参数][文件或者文件夹/支持正则通配] 参数: -i 删 ...

  2. 现在有一个城市销售经理,需要从公司出发,去拜访市内的商家,已知他的位置以及商家的位置,但是由于城市道路交通的原因,他只能在左右中选择一个方向,在上下中选择一个方向,现在问他有多少种方案到达商家地址。给定一个地图map及它的长宽n和m,其中1代表经理位置,2代表商家位置,-1代表不能经过的地区,0代表可以经过的地区,请返回方案数,保证一定存在合法路径。保证矩阵的长宽都小于等于10。

    include "stdafx.h" #include<iostream> #include<vector> #include<algorithm&g ...

  3. 有一个长为n的数组A,求满足0≤a≤b<n的A[b]-A[a]的最大值。 给定数组A及它的大小n,请返回最大差值。

    // ConsoleApplication10.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #include <iostream& ...

  4. 给定一个整数数组nums和一个整数目标值target,请你在该数组中找出和为目标值target的那两个整数,并返回它们的数组下标。

    /** * 给定一个整数数组nums和一个整数目标值target,请你在该数组中找出和为目标值target的那两个整数,并返回它们的数组下标. * * 你可以假设每种输入只会对应一个答案.但是,数组中 ...

  5. 谷歌笔试题--给定一个集合A=[0,1,3,8](该集合中的元素都是在0,9之间的数字,但未必全部包含), 指定任意一个正整数K,请用A中的元素组成一个大于K的最小正整数。

    谷歌笔试题--给定一个集合A=[0,1,3,8](该集合中的元素都是在0,9之间的数字,但未必全部包含), 指定任意一个正整数K,请用A中的元素组成一个大于K的最小正整数. Google2009华南地 ...

  6. 给定一个英文字符串,请编写一个PHP函数找出这个字符串中首先出现三次的那个英文字符(需要区分大小写),并返回

    给定一个英文字符串,请编写一个PHP函数找出这个字符串中首先出现三次的那个英文字符(需要区分大小写),并返回 //统计字符串中出现的字符的出现次数 public function strNum(){ ...

  7. 给定一个double类型的数组arr,其中的元素可正可负可0,返回子数组累乘的最大乘积。例如arr=[-2.5,4,0,3,0.5,8,-1],子数组[3,0.5,8]累乘可以获得最大的乘积12,所以返回12。

    分析,是一个dp的题目, 设f[i]表示以i为结尾的最大值,g[i]表示以i结尾的最小值,那么 f[i+1] = max{f[i]*arr[i+1], g[i]*arr[i+1],arr[i+1]} ...

  8. 基础作业 本周没上课,但是请大家不要忘记学习。 本周请大家完成上周挑战作业的第一部分:给定一个整数数组(包含正负数),找到一个具有最大和的子数组,返回其最大的子数组的和。 例如:[1, -2, 3, 10, -4, 7, 2, -5]的最大子数组为[3, 10, -4, 7, 2] 输入: 请建立以自己英文名字命名的txt文件,并输入数组元素数值,元素值之间用逗号分隔。 输出 在不删除原有文件内容

    1丶 实验代码 #include<stdio.h> int main(void) { int tt,nn,i,j,c[11][11]; int flag=1; scanf("%d ...

  9. 给定一个只包含正整数的非空数组,返回该数组中重复次数最多的前N个数字 ,返回的结果按重复次数从多到少降序排列(N不存在取值非法的情况)

    """ #给定一个只包含正整数的非空数组,返回该数组中重复次数最多的前N个数字 #返回的结果按重复次数从多到少降序排列(N不存在取值非法的情况) 解题思路: 1.设定一个 ...

  10. 最短路径(给定一个包含非负整数的 m x n 网格,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。 说明:每次只能向下或者向右移动一步。)

    给定一个包含非负整数的 m x n 网格,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小. 说明:每次只能向下或者向右移动一步. 例: 输入: [ [1,3,1], [1,5,1], [ ...

随机推荐

  1. U-boot分析之编译体验

    1. 如图可以看到的是PC和嵌入式系统的区别 PC第一步是上电,进入BIOS而嵌入式系统进入bootloader 接着进入操作系统而嵌入式式进入Linux内核 PC识别C盘,D盘,而嵌入式系统则挂载根 ...

  2. vs调试导入功能时莫名自动结束调试

    新装了vs2022,默认下图所示的地方打勾,导致调试文件导入功能时触发了自动结束调试,真是坑爹~~

  3. Flask CURD(增删改查)

    1.创建flask项目 2.修改配置文件: ''' config.py 保存项目配置 ''' 导入Flask模块 from flask import Flask 额外安装: 数据库操作模块 from ...

  4. 驱动开发:配置Visual Studio驱动开发环境

    在正式开始驱动开发之前,需要自行搭建驱动开发的必要环境,首先我们需要安装Visual Studio 2013这款功能强大的程序开发工具,在课件内请双击ISO文件并运行内部的vs_ultimate.ex ...

  5. Spring--案例:数据源对象管理

    案例:数据源对象管理 对于已经学过数据库的我来说,这看起来就像是连接数据库的操作: 就像javaweb项目里面的db.properties文件的使用一样,我们需要先导入一个包,(我用的是Maven项目 ...

  6. Spring Boot 入门学习笔记

    0x01 前言 ​ 大一选修课C++/JAVA二选一,选学了C++.但在后续课程中,发现JAVA的用途很多,所以简单学习了JAVA的语法.同时,也开始了我的Spring Boot 春季|家 (spri ...

  7. 同步协程的必备工具: WaitGroup

    1. 简介 本文将介绍 Go 语言中的 WaitGroup 并发原语,包括 WaitGroup 的基本使用方法.实现原理.使用注意事项以及常见的使用方式.能够更好地理解和应用 WaitGroup 来协 ...

  8. uniapp踩坑必备笔记

    1.[配置]应用版本号名称有一个规则的字符串:1.0.0,规则是:大版本号,中版本号,小版本号. 2.[配置]应用版本号中的小版本号不能超过9,超过9的需要向上一个版本号进一(逢十进一). 3.[配置 ...

  9. [ACM]Uva572-Oil Deposits-DFS应用

    #include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> usin ...

  10. 集合-ArrayList 源码分析

    1.概述 ArrayList 是一种变长的集合类,基于定长数组实现.ArrayList 允许空值和重复元素,当往 ArrayList 中添加的元素数量大于其底层数组容量时,其会通过扩容机制重新生成一个 ...