15.三数之和---javascript版

给定一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?找出所有满足条件且不重复的三元组。

注意:答案中不可以包含重复的三元组。

例如, 给定数组 nums = [-1, 0, 1, 2, -1, -4],

满足要求的三元组集合为:
[
  [-1, 0, 1],
  [-1, -1, 2]
]

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/3sum
 

/**
 *  三数之和 ---排序+去重+双指针
 * @param {*} nums 
 */
var threeSum2 = function(nums) {
    let ans = [];
    const len = nums.length;
    if(nums == null || len < 3) return ans;//nums为空或者小于3返回
    nums.sort((a, b) => a - b); // 排序
    for (let i = 0; i < len ; i++) {
        if(nums[i] > 0) break; // 如果当前数字大于0,则三数之和一定大于0,所以结束循环
        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;
};

 

你提供的数据是一组**非等间隔时间戳的数值序列**,形式如下: ``` 时间戳(精确到毫秒) 数值 2025-09-5 8:37:30.308 9.9728 ... 2025-09-5 9:20:14.572 10.1292 ``` 你的目标是:**将这些不规则采样的数据“匹配”为每秒一个值的时间序列(即每秒一条记录)**,这在工业数据处理、时序数据分析中非常常见。 --- ### ✅ 目标说明 你希望使用 **Kettle(Pentaho Data Integration / Spoon)** 工具来完成这个任务。我们将通过 Kettle 的转换(Transformation)实现以下功能: 1. 解析时间戳字段。 2. 构建一个从起始到结束的**每秒时间序列**(辅助表/流)。 3. 将原始数据与每秒时间对齐,采用**前向填充(Last Observation Carried Forward, LOCF)** 或 **插值法** 填充缺失值。 4. 输出每秒一条记录的结果。 --- ## 🛠️ 使用 Kettle 实现每秒时间序列对齐(Spoon 可视化方案) 以下是完整的 Spoon 转换设计思路和组件配置。 --- ### 🔧 步骤一:输入原始数据(`Text file input`) 假设你的数据保存在 `data.txt` 文件中。 - 添加组件:**Text file input** - 配置: - 文件名:`data.txt` - 分隔符:`\t`(制表符) - 字段: - `timestamp_str` → String - `value` → Number (Double) > 注意:时间戳是字符串,需要后续解析。 --- ### 🔧 步骤二:解析时间戳(`Select values` + `Modified Java Script Value` 或 `Calculator`) #### 方法 A:使用 `Modified Java Script Value` 添加组件:**Modified Java Script Value** ```javascript // 将字符串时间转为 Date 对象 var ts = createDate(timestamp_str, "yyyy-MM-dd HH:mm:ss.SSS"); ts; ``` 输出字段命名为 `timestamp`,类型为 Date。 #### 方法 B:使用 `String to Date` 步骤(推荐更稳定) 添加组件:**String to Date** - 字段名:`timestamp_str` - 目标字段名:`timestamp` - 格式:`yyyy-MM-dd HH:mm:ss.SSS` --- ### 🔧 步骤三:获取最小/最大时间(用于生成时间轴) 使用 **`Group by`** 组件计算时间范围: - 聚合字段: - `Min of timestamp` → `min_time` - `Max of timestamp` → `max_time` 然后使用 **`Get System Info`** 或 **JavaScript** 生成从 `min_time` 到 `max_time` 每秒递增的时间流。 --- ### 🔧 步骤四:生成每秒时间序列(核心技巧) Kettle 没有内置“生成序列”的步骤,但可以用以下方式模拟: #### 方案:使用 **`Generate Rows`** + **JavaScript 时间循环** ##### ① 先用 `JavaScript` 计算总秒数差 添加组件:**Modified Java Script Value** ```javascript // 输入 min_time 和 max_time 是 Date 类型 var diff_ms = max_time.getTime() - min_time.getTime(); var diff_seconds = Math.floor(diff_ms / 1000) + 1; // 包含末尾 diff_seconds; ``` 输出字段:`total_seconds`(整数) ##### ② 使用 `Generate Rows` 生成 0 到 N 的行 添加组件:**Generate Rows** - 生成记录数:留空(动态?不可行),所以先固定大数或预估后设置。 - 字段: - `counter` → Integer,从 0 开始 ⚠️ 缺点:不能直接动态控制行数。建议用外部脚本或预知范围。 替代方案:使用 **用户自定义常量** + 外部参数传入范围。 或者更简单:**先导出 min/max → 再用 Generate Rows 手动设数量** 例如: - min_time = `2025-09-05 08:37:30` - max_time = `2025-09-05 09:20:15` - 总共约 42分钟 ≈ 2520 秒 → 设置 Generate Rows 输出 2520 行 ##### ③ 添加时间偏移 接上 `Generate Rows` 后,加 **`JavaScript` 或 `Calculator`** ```javascript // 在 Modified Java Script Value 中: new Date(min_time.getTime() + counter * 1000); ``` 输出字段:`second_timestamp`(Date) 这样你就得到了一个每秒的时间序列! --- ### 🔧 步骤五:排序并合并两个流(原始数据 & 每秒时间轴) 你需要把两个数据流合并: 1. 原始带 value 的数据流(含 timestamp) 2. 每秒时间轴流(含 second_timestamp) 使用 **`Merge join`** 步骤: - 条件:按时间字段排序 - 连接类型:Left join(以每秒时间为主) - 关键字段:`timestamp` vs `second_timestamp`(需统一字段名) 📌 提示:先分别对两个流使用 **`Sort rows`** 按时间升序排序。 --- ### 🔧 步骤六:向前填充(LOCF)处理空值 由于左连接后大部分 `value` 为空,需进行 **Last Observation Carried Forward** Kettle 不支持直接 LOCF,可用以下方法: #### ✅ 推荐:使用 `User Defined Java Class` (UDJC) 编写简单的 Java 脚本记忆上一个非空值: ```java // Field: value_filled Object[] row = getRow(); if (row == null) { setOutputDone(); return false; } Double lastValue = (Double)getVariable("last_value", null); Double currentValue = (Double) row[ indexOfValue("value") ]; if (currentValue != null) { lastValue = currentValue; } else { // 如果当前为空,保持 lastValue 不变 } setVariable("last_value", lastValue.toString()); // 输出新行 putRow(data.outputRowMeta, new Object[]{ row[0], lastValue }); ``` > 注意:需正确索引字段,此为示意代码。 #### 替代方案(近似):使用 `Analytic Query` 步骤 添加字段: ```sql LAG(value, 1) OVER (ORDER BY second_timestamp) ``` 但这只能取前一行,不能持续传播。效果有限。 --- ### 🔧 步骤七:输出结果(CSV / Table / Excel) 使用 **Text file output** 输出最终每秒数据: - 字段: - `second_timestamp` → 格式化为 `yyyy-MM-dd HH:mm:ss` - `value_filled` → 填充后的值 --- ## 📊 示例输出 | second_timestamp | value_filled | |------------------------|--------------| | 2025-09-05 08:37:30 | 9.9728 | | 2025-09-05 08:37:31 | 10.0674 | | 2025-09-05 08:37:32 | 10.2048 | | ... | ... | | 2025-09-05 08:42:55 | 10.2416 | | 2025-09-05 08:42:56 | 10.2416 | ← 前向填充 | ... | 10.2416 | | 2025-09-05 09:20:14 | 10.1778 | | 2025-09-05 09:20:15 | 10.1292 | --- ## ⚙️ 完整流程图(Spoon 转换结构) ``` [Text File Input] ↓ [String to Date] → timestamp ↓ [Copy Rows to Result] → 用于 Group By 获取 min/max ❌ 不行! ↓ [Blocking Step] or 分支 → 一路去统计 min/max,一路保留原始数据 ↘ ↙ [Wait for] → 等待统计完成 ↓ [Generate Rows] (根据 total_seconds) ↓ [JavaScript] add seconds to min_time → second_timestamp ↓ [Sort Rows] on second_timestamp ↓ [Merge Join] on timestamp = second_timestamp ↓ [User Defined Java Class] → LOCF 填充 value ↓ [Select Values] 清理字段 ↓ [Text File Output] ``` > ⚠️ 技术难点:Kettle 流水线是流式的,无法轻易让“生成行数”依赖前面的聚合结果。解决办法: > > - **方案1**:分两步执行(先跑一次获取时间范围,再跑主转换) > - **方案2**:使用作业(Job)串联两个 Transformation > - **方案3**:用 Python/Shell 预处理生成时间轴 CSV,导入 Kettle --- ## ✅ 更优建议:混合使用 Python 预处理 + Kettle 对于复杂时间序列对齐,建议: 1. 用 Python 脚本先将原始数据 resample 成每秒 LOCF; 2. 输出标准 CSV; 3. 再用 Kettle 做后续 ETL(清洗、加载数据库等); ### 🐍 Python 实现(备选参考) ```python import pandas as pd # 读取数据 df = pd.read_csv('data.txt', sep='\t', header=None, names=['timestamp', 'value']) df['timestamp'] = pd.to_datetime(df['timestamp'], format='%Y-%m-%d %H:%M:%S.%f') # 设置时间为索引 df.set_index('timestamp', inplace=True) # 重采样到每秒,前向填充 result = df.resample('1S').ffill() # 可选:限制只覆盖原始时间范围内的每秒 result.reset_index().to_csv('output_per_second.csv', index=False, date_format='%Y-%m-%d %H:%M:%S') ``` 这个比 Kettle 简洁得多! --- ## ✅ 总结 | 方法 | 优点 | 缺点 | |------|------|-------| | 纯 Kettle 实现 | 全图形化、可集成进 ETL 流程 | 复杂、难以动态生成时间轴 | | Kettle + 外部控制 | 灵活 | 需要多步协调 | | Python 预处理 + Kettle | 快速准确、适合时间序列 | 引入外部语言 | ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值