本题 题目链接

题目描述


我的题解

方法三双100%, 方法一 适合范围广

方法一:双指针(也叫 滑动窗口)

思路分析

  • 用两个指针i和表示当前枚举到的以i为起点,j为终点的区间,sum表示[i,j]的区间和:

    • 当sum < tiarget,j指针向前移动,扩大区间,增大区间和。即:j++,sum+=j ;
    • 当sum > target,i指针向前移动,收缩区间,减小区间和。即:sum-=i,i++;
    • 当sum == target,i指针向前移动2个单位,j向前移动一个单位。即sum = sum-i-(i+1),i-=2,j++,sum+=j;

      (当sum=target时,无论是 i 先向前移动,还是 j 先向前移动,另一个指针下一步都会向前一步,此时,一定有sum>target(剔除一个小的加进来一个大的数)。

      故而可以直接把 i++和 j++合成一步。又因sum>target,i 又会向前一步。故最终可以再把这两步合成一步,直接令sum=target时,i 向前移动两个单位而j向前移动1个单位)
  • (对于求区间和sum也可以用数学公式求啦:(连续序列和=(首项+末项)*项数/2))

代码如下

    public int[][] findContinuousSequence(int target) {
ArrayList<int[]> resLists = new ArrayList<>();
int sum = 1;
for (int i = 1,j = 1; j <= (target >>1) + 1; ) {
if (sum < target) {
j++;
sum += j;
} else if (sum > target) {
sum -= i;
i++;
} else {
resLists.add(getArray(i,j));
j++;
sum = sum + j - i - (i + 1);
i = i+2;
}
}
return resLists.toArray(new int[0][]);
} private int[] getArray(int i, int j) {
if (i == j) return new int[0]; // 题目要求至少含2个数
int[] arr = new int[(j - i + 1)];
for (int k = 0; k <= j - i; k++) arr[k] = k + i; return arr;
}

方法二:求根公式

(官方的题解,我就不写了,直接截图附上C++代码)

代码如下(C++)

class Solution {
public:
vector<vector<int>> findContinuousSequence(int target) {
vector<vector<int>> vec;
vector<int> res;
int sum = 0, limit = (target - 1) / 2; // (target - 1) / 2 等效于 target / 2 下取整
for (int x = 1; x <= limit; ++x) {
long long delta = 1 - 4 * (x - 1ll * x * x - 2 * target);
if (delta < 0) continue;
int delta_sqrt = (int)sqrt(delta + 0.5);
if (1ll * delta_sqrt * delta_sqrt == delta && (delta_sqrt - 1) % 2 == 0){
int y = (-1 + delta_sqrt) / 2; // 另一个解(-1-delta_sqrt)/2必然小于0,不用考虑
if (x < y) {
res.clear();
for (int i = x; i <= y; ++i) res.emplace_back(i);
vec.emplace_back(res);
}
}
}
return vec;
}
};

方法三:等差数列特殊性质,奇偶讨论,双100

(参考了一位大佬的)

思路分析

  • 实际上某个序列可以按其包含奇数/偶数个元素来讨论

    • 当某序列含有奇数个(2k+1)元素时,Sequence : i, i+1, i+2 ... i+2k

      其序列和为中间元素的2k+1倍,即:Sum(Sequence) = (2k+1) * (i+k)
    • 当某序列含有偶数个(2k)元素时, Sequence : i, i+1, i+2 ... i+2k-1

      其序列和为中间两个元素的k倍,即:Sum(Sequence) = k * [(i+k-1) + (i+k)]
  • 因此枚举所有可能的序列长度len(从2开始,题目要求至少2个连续的数):

    • 奇数时直接判断长度len是否整除target,整除则符合题意,找到序列
    • 偶数时判断 2k*(mid1+mid2) = target,k为正整数,mid1和mid2为序列中间的两个数,因连续,故和为大于1的奇数。

      成立,则找到序列
  • 由于枚举按照序列长度递增顺序,因此输出时将结果逆序输出

  • 对于枚举长度,len上界:

代码如下


public int[][] findContinuousSequence(int target) {
ArrayList<int[]> resLists = new ArrayList<>(); int len = 2;
while (len * (1 + len) < (target << 1)) {
if (len % 2 == 1) { // 长度为奇数
if (target % len == 0) { // 找到序列(中间数为 target/len)
int[] arr = new int[len];
for (int i = 0, val = target / len - len / 2; i < len; i++) // 存数组
arr[i] = val++;
resLists.add(arr);
}
} else { // 长度为偶数
int k = len / 2;
// 符合式子: 2k*(mid1+mid2) = target,k为正整数,mid1和mid2为连续的两个数,故和为大于1的奇数
if (target % k == 0 && target / k % 2 == 1) { // 找到序列(中间两个数的和为 target/k)
int[] arr = new int[len];
for (int i = 0, val = target / k / 2 - len / 2 + 1; i < len; i++)
arr[i] = val++;
resLists.add(arr);
}
} len++;
}
Collections.reverse(resLists);
return resLists.toArray(new int[0][]);
}

剑指 Offer 57 - II. 和为s的连续正数序列的更多相关文章

  1. 剑指 Offer 57 - II. 和为s的连续正数序列 + 双指针 + 数论

    剑指 Offer 57 - II. 和为s的连续正数序列 Offer_57_2 题目描述 方法一:暴力枚举 package com.walegarrett.offer; /** * @Author W ...

  2. 力扣 - 剑指 Offer 57 - II. 和为s的连续正数序列

    题目 剑指 Offer 57 - II. 和为s的连续正数序列 思路1(双指针/滑动窗口) 所谓滑动窗口,就是需要我们从一个序列中找到某些连续的子序列,我们可以使用两个for循环来遍历查找,但是未免效 ...

  3. 剑指offer四十一之和为S的连续正数序列

    一.题目   题目描述:小明很喜欢数学,有一天他在做数学作业时,要求计算出9~16的和,他马上就写出了正确答案是100.但是他并不满足于此,他在想究竟有多少种连续的正数序列的和为100(至少包括两个数 ...

  4. LeetCode 题解 | 面试题57 - II. 和为s的连续正数序列

    题目描述 面试题57 - II. 和为s的连续正数序列 难度简单37收藏分享切换为英文关注反馈 输入一个正整数 target ,输出所有和为 target 的连续正整数序列(至少含有两个数). 序列内 ...

  5. 《剑指offer》面试题57 - II. 和为s的连续正数序列

    问题描述 输入一个正整数 target ,输出所有和为 target 的连续正整数序列(至少含有两个数). 序列内的数字由小到大排列,不同序列按照首个数字从小到大排列. 示例 1: 输入:target ...

  6. 剑指offer41:所有和为S的连续正数序列,例如,有多少种连续的正数序列的和为100

    1 题目描述 小明很喜欢数学,有一天他在做数学作业时,要求计算出9~16的和,他马上就写出了正确答案是100.但是他并不满足于此,他在想究竟有多少种连续的正数序列的和为100(至少包括两个数).没多久 ...

  7. [简单-剑指 Offer 53 - II. 0~n-1中缺失的数字]

    [简单-剑指 Offer 53 - II. 0-n-1中缺失的数字] 一个长度为n-1的递增排序数组中的所有数字都是唯一的,并且每个数字都在范围0-n-1之内.在范围0-n-1内的n个数字中有且只有一 ...

  8. 剑指 Offer 68 - II. 二叉树的最近公共祖先 + 最近公共祖先(LCA)

    剑指 Offer 68 - II. 二叉树的最近公共祖先 Offer_68_2 题目详情 题解分析 java代码 package com.walegarrett.offer; /** * @Autho ...

  9. 剑指 Offer 58 - II. 左旋转字符串 + 简单题

    剑指 Offer 58 - II. 左旋转字符串 Offer_58_2 题目描述 java代码 package com.walegarrett.offer; /** * @Author WaleGar ...

随机推荐

  1. python 请使用迭代查找一个list中最小和最大值,并返回一个tuple

    请使用迭代查找一个list中最小和最大值,并返回一个tuple: 要注意返回的值的类型是不是tuple def findMinAndMax(L): min=0 max=0 if len(L)==0: ...

  2. mysql根据逗号分割的字符串去关联查询另外一个表的数据

    1.说明 在做显示数据的时候,一个字段会存那种逗号分割的字符串,那如何去根据逗号分割字符串去查询另一个表的数据呢? 首先我们查看一下需要显示的数据 select * from company wher ...

  3. dotNetCore阅读源码-CreateDefaultBuilder及ConfigureWebHostDefaults内部

    版本:DotNetCore 3.1 CreateDefaultBuilder内部源码: public static IHostBuilder CreateDefaultBuilder(string[] ...

  4. Redis批量查询模板

    场景 在开发的时候经常会遇到批量取缓存的问题,例如查询商品信息 传入一个商品Id列表,查询Redis数据存在则放入返回列表 不存在的数据查找数据库,并放入Redis 上面两步数据整合返回 伪代码为 l ...

  5. PE解析器与加载器编写指南

    PE解析器与加载器编写指南 最近准备去实习,看公司要求应该开发PE相关的查杀引擎,因此再回头复习一下PE格式,重新写一个PE解析器和PE加载器,再此记录下有关坑. PE解析器部分: 1)如何确定节区表 ...

  6. three.js 曲线

    上几篇说了three.js的曲线,这篇来郭先生来说说three.js曲线,在线案例点击郭先生的博客查看. 1. 了解three.js曲线 之前已经说了一些three.js的几何体,这篇说一说three ...

  7. 作为程序员居然没用过这款神器?太out了吧。

    背景 工欲善其事,必先利其器.​后面我将陆陆续续推荐一些软件利器帮助大家提高效率(主要针对 Mac 电脑). 如果你在使用 Mac 电脑,并且没有如某些人那样安装并使用 Windows 系统,那么你可 ...

  8. DVWA(xss部分源码分析)

    前言 DVWA靶场都不陌生,最新学习xss,从新又搞了一遍xss部分,从源码方面康康xss的原因,参考了很多大佬的博客表示感谢,网上也有很多DVWA靶场教程,就水一篇吧. 更多web安全知识欢迎访问: ...

  9. CSS上划线、下划线、删除线等方法

    text-decoration:underline;     下划线 text-decoration:overline;    顶划线 text-decoration:line-through;  删 ...

  10. 史上最全的 jmeter 获取 jdbc 数据使用的四种方法

    jmeter使用jdbc协议获取数据库中数据,很多人都会用,因为大家在做测试的时候,有时候需要大量的用户进行登录,获取需要数据库中真实的数据用于测试,所以常常会用jdbc来获取数据库数据. 那从数据库 ...