Day.10 | 150.逆波兰表达式求值 239.滑动窗口最大值 347.前 K 个高频元素

150.逆波兰表达式求值

要点:确实是没做过的话很难想到解题思路,理解逆波兰表达式是什么,计算机是如何计算数学表达式的

方法:

1. 遍历,找+-*/ 四个符号

2. 碰到符号,就把栈顶的两个元素弹出计算结果

3. 将计算出的结果push入栈

class Solution {
public:
    int evalRPN(vector<string>& tokens) {
        stack<long long> st;
        for (string s : tokens) {
            if (s == "+" || s == "-" || s == "*" || s == "/") {
                long long num1 = st.top();
                st.pop();
                long long num2 = st.top();
                st.pop();
                if (s == "+") st.push(num2 + num1);
                if (s == "-") st.push(num2 - num1);
                if (s == "*") st.push(num2 * num1);
                if (s == "/") st.push(num2 / num1);
            } else {
                st.push(stoll(s));
            }
        }
        long long result = st.top();
        return result;
    }
};

239.滑动窗口最大值

要点:好难。关键点在于实现一个单调递减的队列,这样获取滑动窗口里的最大值,就不用暴力遍历取最大,只用取队列第一个元素就可以了

方法:

1. 自定义单调递减的队列结构,包含3个方法

        1.1 弹出队首最大元素

        1.2 push元素,如果push的元素比当前队尾的大,弹出队尾,再push,保证push的元素前面只有比它大的,没有比它小的

        1.3 找最大,就是返回队首元素

2. 使用自定义结构,push k个元素进去

3. 先把初始化窗口的最大值放进result里

4. 开始遍历第k+1个元素,从这个元素开始,每个元素都要经历pop push getMax的操作,pop保证自定义队列中最多只有k个元素,push保证自定义队列的队首是当前滑动窗口的最大值

class Solution {
private:
    class MyQueue {
    public:
        deque<int> que;
        void pop(int value) {
            if (!que.empty() && value == que.front()) {
                que.pop_front();
            }
        }
        void push(int value) {
            while (!que.empty() && value > que.back()) {
                que.pop_back();
            }
            que.push_back(value);
        }
        int getMax() { return que.front(); }
    };

    public : vector<int>
             maxSlidingWindow(vector<int>& nums, int k) {
        MyQueue que;
        vector<int> result;
        for (int i = 0; i < k; i++) {
            que.push(nums[i]);
        }
        result.push_back(que.getMax());
        for (int i = k; i < nums.size(); i++) {
            que.pop(nums[i - k]);
            que.push(nums[i]);
            result.push_back(que.getMax());
        }
        return result;
    }
};

347.前 K 个高频元素

要点:统计完所有元素出现的频率后,如何给频率排序,以达到题目要求的时间复杂度才是要点。堆排序出现得有点突然,这里没看懂,等看完树之后再回来重温

方法:

1. map+遍历,统计元素出现的频率

2. 给map按value排序,取前k个pair的key

class Solution {
public:
    class myComparison {
    public:
        bool operator()(const pair<int, int>& lhs, const pair<int, int>& rhs) {
            return lhs.second > rhs.second;
        }
    };

    vector<int> topKFrequent(vector<int>& nums, int k) {
        unordered_map<int, int> map;
        for (int i = 0; i < nums.size(); i++) {
            map[nums[i]]++;
        }
        priority_queue<pair<int, int>, vector<pair<int, int>>, myComparison>
            pri_que;
        for (unordered_map<int, int>::iterator it = map.begin();
             it != map.end(); it++) {
            pri_que.push(*it);
            if (pri_que.size() > k) {
                pri_que.pop();
            }
        }
        vector<int> result(k);
        for (int i = k - 1; i >= 0; i--) {
            result[i] = pri_que.top().first;
            pri_que.pop();
        }
        return result;
    }
};
package jnpf.task; import jnpf.entity.EquipmentparameterEntity; import jnpf.entity.UleabnormalrecordsEntity; import jnpf.myutils.DateUtils; import jnpf.service.*; import lombok.extern.slf4j.Slf4j; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.time.*; import java.time.format.DateTimeFormatter; import java.util.*; import java.util.stream.Collectors; @Slf4j @Component public class HAHFAnalysisTask { private static final Logger logger = LoggerFactory.getLogger(HAHFAnalysisTask.class); private static final int BUCKET_SIZE = 6; // 6小时分桶 private static final int MIN_DATA_POINTS = 4; // 最小数据点数 private static final int HOURS_IN_DAY = 24; // 一天的小时数 private static final int RECOVERY_WINDOW_HOURS = 24; // 恢复判断窗口小时数 @Autowired private EquipmentparameterService equipmentparameterService; @Autowired private UleabnormalrecordsService uleabnormalrecordsService; @Autowired private RealDataService realDataService; @Autowired private EquipmentledgerService equipmentledgerService; @Autowired private ProcessmanageService processmanageService; DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); //@XxlJob("hahfAnalysis") public void hahfAnalysis() { logger.info("HAHF分析任务启动"); // 1. 获取TSP设备列表 List<EquipmentparameterEntity> equipmentList = equipmentparameterService.geHAHFList(); if (equipmentList.isEmpty()) { logger.info("没有可分析的TSP设备"); return; } // 2. 准备查询参数 Map<String, Object> params = new HashMap<>(); List<String> tags = equipmentList.stream() .map(EquipmentparameterEntity::getTag) .collect(Collectors.toList()); params.put("tags", tags); // 3. 获取日常值数据 params.put("begindate", DateUtils.dataTimeformat(new Date())); List<Map> dailyValue = realDataService.selectLastmonthDailyvalue(params); Map<String, Map<String, Object>> dailyValueMap = dailyValue.stream() .collect(Collectors.toMap( m -> (String) m.get("datag"), m -> m )); // 4. 获取小时数据(从一天开始时间到当时间) LocalDateTime endTime = LocalDateTime.now(); // 获取一天开始时间(00:00:00) LocalDateTime startTime = LocalDate.now().minusDays(1).atStartOfDay(); params.put("begindate", formatDateTime(startTime)); params.put("enddate", formatDateTime(endTime)); List<Map> hourDataMaps = realDataService.selectHourdataByTagIdsAndDate(params); // 5. 按tag分组小时数据 Map<String, List<Map>> hourDataByTag = hourDataMaps.stream() .collect(Collectors.groupingBy( m -> (String) m.get("datag") )); // 6. 获取当报警中的记录 List<UleabnormalrecordsEntity> activeAlarms = uleabnormalrecordsService.getOnhahfList(); Map<String, UleabnormalrecordsEntity> activeAlarmMap = activeAlarms.stream() .collect(Collectors.toMap( UleabnormalrecordsEntity::getParacode, alarm -> alarm )); // 7. 处理每个设备 for (EquipmentparameterEntity equipment : equipmentList) { try { processEquipment( equipment, dailyValueMap, hourDataByTag, activeAlarmMap, startTime, endTime ); } catch (Exception e) { logger.error("处理设备{}失败: {}", equipment.getEncode(), e.getMessage(), e); } } logger.info("HAHF分析任务完成,共处理{}个设备", equipmentList.size()); } private void processEquipment(EquipmentparameterEntity equipment, Map<String, Map<String, Object>> dailyValueMap, Map<String, List<Map>> hourDataByTag, Map<String, UleabnormalrecordsEntity> activeAlarmMap, LocalDateTime analysisStart, LocalDateTime analysisEnd) { String tag = equipment.getTag(); String paraCode = equipment.getEncode(); // 获取该tag的日常值配置 Map<String, Object> dailyConfig = dailyValueMap.get(tag); if (dailyConfig == null) { logger.warn("设备{}缺少日常值", paraCode); return; } double farBeyondValue = ((Number) dailyConfig.get("farbeyondvalue")).doubleValue(); double limitingValue = ((Number) dailyConfig.get("limitingvalue")).doubleValue(); // 获取该tag的小时数据 List<Map> hourDataList = hourDataByTag.getOrDefault(tag, new ArrayList<>()); // 无小时数据直接返回 if (hourDataList.isEmpty()) { logger.info("设备{}没有小时数据", paraCode); return; } // 准备时间序列数据 List<DataPoint> dataPoints = prepareDataPoints(hourDataList); // 按时间排序 dataPoints.sort(Comparator.comparing(DataPoint::getDateTime)); // 获取最后数据点的时间和值 DataPoint lastDataPoint = dataPoints.get(dataPoints.size() - 1); LocalDateTime lastDataTime = lastDataPoint.dateTime; double lastDataValue = lastDataPoint.value; // 添加调试信息 logger.debug("设备{}有{}个数据点,时间范围: {} 到 {},最后数据点: {}={}", paraCode, dataPoints.size(), dataPoints.get(0).dateTime, dataPoints.get(dataPoints.size()-1).dateTime, lastDataTime, lastDataValue); // 设备有报警中记录 - 无论阈值条件是否满足,都需要检查恢复 if (activeAlarmMap.containsKey(paraCode)) { handleActiveAlarm( activeAlarmMap.get(paraCode), dataPoints, farBeyondValue, limitingValue, analysisEnd, lastDataTime, lastDataValue ); } // 设备无报警中记录 - 只有满足阈值条件时才处理 else { // 检查是否满足报警条件 boolean isValidForAlarm = isValidForAlarm(dataPoints, farBeyondValue, limitingValue); if (isValidForAlarm) { handleNewAlarm( equipment, dataPoints, farBeyondValue, limitingValue, analysisEnd, lastDataTime, lastDataValue ); } else { logger.info("设备{}数据不满足报警条件", paraCode); } } } // ===================== 报警处理核心逻辑 ===================== /** * 处理新报警检测 */ private void handleNewAlarm(EquipmentparameterEntity equipment, List<DataPoint> dataPoints, double farBeyondValue, double limitingValue, LocalDateTime analysisEnd, LocalDateTime lastDataTime, double lastDataValue) { // 寻找所有符合条件的连续时间段 List<TimePeriod> validPeriods = findValidPeriods(dataPoints, farBeyondValue, limitingValue, lastDataTime, analysisEnd); if (validPeriods.isEmpty()) { logger.info("设备{}满足阈值条件但未找到有效时间段", equipment.getEncode()); return; } // 合并连续的时间段 List<TimePeriod> mergedPeriods = mergeContinuousPeriods(validPeriods); // 创建报警记录 for (TimePeriod period : mergedPeriods) { // 确定实际报警开始和结束时间 LocalDateTime actualStart = findActualStartTime(dataPoints, period.start, farBeyondValue, limitingValue); LocalDateTime actualEnd = findActualEndTime(dataPoints, period.end, farBeyondValue, limitingValue, analysisEnd); createAlarmRecord(equipment, actualStart, actualEnd); } } /** * 处理活跃报警 */ private void handleActiveAlarm(UleabnormalrecordsEntity activeAlarm, List<DataPoint> dataPoints, double farBeyondValue, double limitingValue, LocalDateTime analysisEnd, LocalDateTime lastDataTime, double lastDataValue) { LocalDateTime alarmStartTime = toLocalDateTime(activeAlarm.getAbnormaltime()); // 检查报警是否恢复:连续24小时不满足条件才算恢复 LocalDateTime recoveryTime = checkRecovery( dataPoints, alarmStartTime, farBeyondValue, limitingValue, analysisEnd ); // 情况1: 报警恢复 if (recoveryTime != null) { completeAlarm(activeAlarm, recoveryTime); // 检查恢复后是否再次触发报警 List<DataPoint> postRecoveryData = dataPoints.stream() .filter(point -> point.dateTime.isAfter(recoveryTime)) .collect(Collectors.toList()); if (!postRecoveryData.isEmpty()) { DataPoint lastPostDataPoint = postRecoveryData.get(postRecoveryData.size() - 1); if (isValidForAlarm(postRecoveryData, farBeyondValue, limitingValue)) { EquipmentparameterEntity equipment = new EquipmentparameterEntity(); equipment.setEncode(activeAlarm.getParacode()); equipment.setTag(activeAlarm.getParacode()); equipment.setEquipmentledgerid(activeAlarm.getEquipmentid()); equipment.setFullname(activeAlarm.getParaname()); handleNewAlarm( equipment, postRecoveryData, farBeyondValue, limitingValue, analysisEnd, lastPostDataPoint.dateTime, lastPostDataPoint.value ); } } } // 情况2: 报警持续中 else { // 检查最后一个数据点是否仍超过阈值,确保报警状态正确 if (lastDataValue >= limitingValue) { logger.info("报警{}仍在持续中,已持续{}小时", activeAlarm.getId(), Duration.between(alarmStartTime, LocalDateTime.now()).toHours()); } else { // 最后一个点低于阈值但未满足恢复条件,可能是短暂波动 logger.info("报警{}最后数据点低于阈值但未确认恢复,继续观察", activeAlarm.getId()); } } } // ===================== 报警检测算法 ===================== /** * 核心算法:寻找有效时间段 */ private List<TimePeriod> findValidPeriods(List<DataPoint> dataPoints, double farBeyondValue, double limitingValue, LocalDateTime lastDataTime, LocalDateTime analysisEnd) { List<TimePeriod> validPeriods = new ArrayList<>(); if (dataPoints.size() < MIN_DATA_POINTS) { return validPeriods; } // 按日期和时间排序 dataPoints.sort(Comparator.comparing(DataPoint::getDateTime)); // 使用滑动窗口检测24小时时间段 int i = 0; while (i < dataPoints.size()) { LocalDateTime windowStart = dataPoints.get(i).dateTime; LocalDateTime windowEnd = windowStart.plusHours(HOURS_IN_DAY); // 获取窗口内的数据点 List<DataPoint> windowData = new ArrayList<>(); int j = i; while (j < dataPoints.size()) { DataPoint point = dataPoints.get(j); if (point.dateTime.isBefore(windowEnd)) { windowData.add(point); j++; } else { break; } } // 检查窗口有效性 if (isValidPeriod(windowData, farBeyondValue, limitingValue, windowStart, windowEnd)) { // 确定时间段结束时间 LocalDateTime periodEnd; // 如果窗口结束时间在最后数据时间之后,且最后数据仍超过阈值,则结束时间为null(持续中) if (windowEnd.isAfter(lastDataTime) && lastDataTime.isAfter(windowStart) && dataPoints.get(dataPoints.size() - 1).value >= limitingValue) { periodEnd = null; } else { periodEnd = windowEnd; } validPeriods.add(new TimePeriod(windowStart, periodEnd)); // 移动到窗口结束位置,避免重复检测 i = j; } else { i++; } } return validPeriods; } /** * 检查24小时窗口是否有效 */ private boolean isValidPeriod(List<DataPoint> dataPoints, double farBeyondValue, double limitingValue, LocalDateTime windowStart, LocalDateTime windowEnd) { if (dataPoints.isEmpty()) { return false; } // 检查时间跨度是否足够(至少24小时) Duration duration = Duration.between(windowStart, windowEnd); if (duration.toHours() < HOURS_IN_DAY) { return false; } // 检查限制值条件 - 窗口内所有数据点都要大于等于limitingValue boolean allAboveLimiting = dataPoints.stream() .allMatch(point -> point.value >= limitingValue); if (!allAboveLimiting) { return false; } // 按6小时分桶组织数据 Map<Integer, List<DataPoint>> bucketMap = new HashMap<>(); for (DataPoint point : dataPoints) { int bucketIdx = point.dateTime.getHour() / BUCKET_SIZE; bucketMap.computeIfAbsent(bucketIdx, k -> new ArrayList<>()).add(point); } // 检查每个桶是否满足条件:每个6小时桶至少有一个点远高于日常值 for (int bucketIdx = 0; bucketIdx < 4; bucketIdx++) { List<DataPoint> bucketData = bucketMap.getOrDefault(bucketIdx, new ArrayList<>()); // 桶内无数据或没有有效点 if (bucketData.isEmpty() || bucketData.stream().noneMatch(point -> point.value >= farBeyondValue)) { return false; } } return true; } /** * 检查报警恢复:需要连续24小时不满足报警条件 */ private LocalDateTime checkRecovery(List<DataPoint> dataPoints, LocalDateTime startTime, double farBeyondValue, double limitingValue, LocalDateTime analysisEnd) { if (dataPoints.isEmpty()) { return null; } // 过滤出报警开始时间之后的数据 List<DataPoint> postAlarmData = dataPoints.stream() .filter(point -> !point.dateTime.isBefore(startTime)) .collect(Collectors.toList()); if (postAlarmData.isEmpty()) { return null; } // 检查是否有连续24小时不满足条件 for (int i = 0; i < postAlarmData.size(); i++) { LocalDateTime windowStart = postAlarmData.get(i).dateTime; LocalDateTime windowEnd = windowStart.plusHours(RECOVERY_WINDOW_HOURS); // 如果窗口超出分析结束时间,则调整窗口结束时间 if (windowEnd.isAfter(analysisEnd)) { windowEnd = analysisEnd; } // 获取窗口内的数据点 List<DataPoint> windowData = new ArrayList<>(); for (int j = i; j < postAlarmData.size(); j++) { DataPoint point = postAlarmData.get(j); if (point.dateTime.isBefore(windowEnd)) { windowData.add(point); } else { break; } } // 检查窗口是否满足恢复条件:不满足报警条件 if (!isValidPeriod(windowData, farBeyondValue, limitingValue, windowStart, windowEnd)) { // 找到第一个不满足条件的点作为恢复开始时间 for (DataPoint point : windowData) { if (point.value < limitingValue) { return point.dateTime; } } // 如果所有点都高于limitingValue但不满足其他条件,取窗口第一个点时间 return windowData.get(0).dateTime; } } return null; } /** * 检查是否满足报警条件 */ private boolean isValidForAlarm(List<DataPoint> dataPoints, double farBeyondValue, double limitingValue) { if (dataPoints.size() < MIN_DATA_POINTS) { return false; } // 检查是否有至少24小时的连续数据满足条件 for (int i = 0; i < dataPoints.size(); i++) { LocalDateTime windowStart = dataPoints.get(i).dateTime; LocalDateTime windowEnd = windowStart.plusHours(HOURS_IN_DAY); // 获取窗口内的数据点 List<DataPoint> windowData = new ArrayList<>(); for (int j = i; j < dataPoints.size(); j++) { DataPoint point = dataPoints.get(j); if (point.dateTime.isBefore(windowEnd)) { windowData.add(point); } else { break; } } if (isValidPeriod(windowData, farBeyondValue, limitingValue, windowStart, windowEnd)) { return true; } } return false; } // ===================== 报警记录管理 ===================== /** * 创建报警记录 */ private void createAlarmRecord(EquipmentparameterEntity equipment, LocalDateTime startTime, LocalDateTime endTime) { try { UleabnormalrecordsEntity record = new UleabnormalrecordsEntity(); record.setParacode(equipment.getEncode()); record.setAbnormaltime(toDate(startTime)); record.setCompletetime(toDate(endTime)); // 计算持续时间(分钟) if (endTime != null) { long durationSeconds = Duration.between(startTime, endTime).getSeconds(); record.setDuration((int) (durationSeconds / 60)); } else { // 对于持续中的报警,计算从开始到现在的持续时间 long durationSeconds = Duration.between(startTime, LocalDateTime.now()).getSeconds(); record.setDuration((int) (durationSeconds / 60)); } record.setAbnormaltype("700229026538590853"); record.setAbnormalstate(endTime == null ? "0" : "1"); // 0-报警中, 1-已结束 String processName = getProcessname(equipment.getEquipmentledgerid()); String equipName = getEquipname(equipment.getEquipmentledgerid()); if (endTime == null) { record.setAbnormaldescribe( "【" + processName + "】工序-【" + equipName + "】设备-【" + equipment.getFullname() + "】参数,于(" + df.format(record.getAbnormaltime()) + ")出现高频高幅事件,请往治理" ); } else { record.setAbnormaldescribe( "【" + processName + "】工序-【" + equipName + "】设备-【" + equipment.getFullname() + "】参数,于(" + df.format(record.getAbnormaltime()) + ")至(" + df.format(record.getCompletetime()) + ")出现高频高幅事件" ); } record.setProcess(equipmentledgerService.getInfo(equipment.getEquipmentledgerid()).getProcesscode()); record.setEquipmentid(equipment.getEquipmentledgerid()); record.setEquipmenttype(equipmentledgerService.getInfo(equipment.getEquipmentledgerid()).getEquipmenttype()); record.setEquipmentcode(equipmentledgerService.getInfo(equipment.getEquipmentledgerid()).getDevicecode()); record.setParacode(equipment.getEncode()); record.setParaname(equipment.getFullname()); record.setAbnormalcode("7"); record.setCreatortime(new Date()); record.setCreatoruserid("349057407209541"); uleabnormalrecordsService.save(record); if (endTime == null) { logger.info("创建新报警记录: {} - 开始时间: {} (持续中)", equipment.getEncode(), startTime); } else { logger.info("创建完整报警记录: {} - 开始: {}, 结束: {} (持续{}小时)", equipment.getEncode(), startTime, endTime, Duration.between(startTime, endTime).toHours()); } } catch (Exception e) { logger.error("创建报警记录失败: {}", e.getMessage(), e); } } /** * 完成报警处理 */ private void completeAlarm(UleabnormalrecordsEntity alarm, LocalDateTime recoveryTime) { try { alarm.setCompletetime(toDate(recoveryTime)); LocalDateTime startTime = toLocalDateTime(alarm.getAbnormaltime()); long durationSeconds = Duration.between(startTime, recoveryTime).getSeconds(); alarm.setDuration((int) (durationSeconds / 60)); alarm.setAbnormalstate("1"); alarm.setLastmodifytime(new Date()); alarm.setLastmodifyuserid("349057407209541"); uleabnormalrecordsService.updateById(alarm); long durationHours = Duration.between(startTime, recoveryTime).toHours(); logger.info("报警{}已恢复,开始时间: {},结束时间: {},持续小时: {}", alarm.getId(), startTime, recoveryTime, durationHours); } catch (Exception e) { logger.error("完成报警处理失败: {}", e.getMessage(), e); } } // ===================== 辅助方法 ===================== private List<DataPoint> prepareDataPoints(List<Map> hourDataList) { return hourDataList.stream() .map(map -> new DataPoint( (String) map.get("datadt"), ((Number) map.get("avgdata")).doubleValue() )) .collect(Collectors.toList()); } private LocalDateTime findActualStartTime(List<DataPoint> dataPoints, LocalDateTime windowStart, double farBeyondValue, double limitingValue) { // 向查找实际的异常开始时间 for (DataPoint point : dataPoints) { if (point.dateTime.isAfter(windowStart)) { break; } if (point.value >= limitingValue) { return point.dateTime; } } return windowStart; } private LocalDateTime findActualEndTime(List<DataPoint> dataPoints, LocalDateTime windowEnd, double farBeyondValue, double limitingValue, LocalDateTime analysisEnd) { if (windowEnd == null) { return null; } // 按时间排序数据点 dataPoints.sort(Comparator.comparing(DataPoint::getDateTime)); // 找到窗口结束时间后的第一个数据点索引 int startIndex = -1; for (int i = 0; i < dataPoints.size(); i++) { if (dataPoints.get(i).dateTime.isAfter(windowEnd)) { startIndex = i; break; } } if (startIndex == -1) { // 没有找到窗口结束时间后的数据点 return windowEnd; } // 按6小时分桶组织所有数据 Map<Integer, List<DataPoint>> bucketMap = new HashMap<>(); for (DataPoint point : dataPoints) { int bucketIdx = point.dateTime.getHour() / 6; bucketMap.computeIfAbsent(bucketIdx, k -> new ArrayList<>()).add(point); } // 检查每个时间点是否满足报警条件 for (int i = startIndex; i < dataPoints.size(); i++) { DataPoint point = dataPoints.get(i); // 检查条件1: 数据是否低于limitingValue if (point.value < limitingValue) { return point.dateTime; } // 检查条件2: 当时间点所属的桶是否满足farBeyondValue条件 int currentBucket = point.dateTime.getHour() / 6; List<DataPoint> bucketData = bucketMap.getOrDefault(currentBucket, new ArrayList<>()); // 检查当桶内是否有数据点大于farBeyondValue boolean hasFarBeyondValue = bucketData.stream() .anyMatch(p -> p.value >= farBeyondValue); // 如果当桶内没有数据点达到farBeyondValue if (!hasFarBeyondValue) { // 查找当桶内第一个数据点的时间 Optional<DataPoint> firstPointInBucket = bucketData.stream() .min(Comparator.comparing(DataPoint::getDateTime)); if (firstPointInBucket.isPresent()) { return firstPointInBucket.get().dateTime; } else { return point.dateTime; } } } // 如果没有找到不满足条件的点,返回窗口结束时间 return windowEnd; } private String formatDateTime(LocalDateTime dateTime) { return dateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); } private Date toDate(LocalDateTime localDateTime) { if (localDateTime == null) { return null; } return Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant()); } private LocalDateTime toLocalDateTime(Date date) { if (date == null) { return null; } return LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault()); } /** * 合并连续的时间段 */ private List<TimePeriod> mergeContinuousPeriods(List<TimePeriod> periods) { if (periods.isEmpty()) { return periods; } // 按开始时间排序 periods.sort(Comparator.comparing(p -> p.start)); List<TimePeriod> merged = new ArrayList<>(); TimePeriod current = periods.get(0); for (int i = 1; i < periods.size(); i++) { TimePeriod next = periods.get(i); // 如果当时间段结束时间与下一个时间段开始时间相差不超过24小时,则合并 if (current.end != null && next.start != null && Duration.between(current.end, next.start).toHours() <= 24) { current.end = next.end; } else { merged.add(current); current = next; } } merged.add(current); return merged; } // ===================== 辅助类 ===================== private static class DataPoint { LocalDateTime dateTime; double value; DataPoint(String dateStr, double value) { try { // 尝试解析多种可能的时间格式 if (dateStr.contains("T")) { // ISO格式: yyyy-MM-ddTHH:mm:ss this.dateTime = LocalDateTime.parse(dateStr, DateTimeFormatter.ISO_LOCAL_DATE_TIME); } else if (dateStr.length() == 16 && dateStr.contains(":")) { // 格式: yyyy-MM-dd HH:mm this.dateTime = LocalDateTime.parse(dateStr, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm")); } else if (dateStr.length() == 13 && dateStr.contains(" ")) { // 格式: yyyy-MM-dd HH this.dateTime = LocalDateTime.parse(dateStr + ":00:00", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); } else if (dateStr.length() == 10 && dateStr.contains("-")) { // 格式: yyyy-MM-dd this.dateTime = LocalDateTime.parse(dateStr + " 00:00:00", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); } else { // 默认尝试ISO格式 this.dateTime = LocalDateTime.parse(dateStr, DateTimeFormatter.ISO_LOCAL_DATE_TIME); } } catch (Exception e) { logger.error("解析时间字符串失败: {}", dateStr, e); throw new RuntimeException("时间格式解析失败: " + dateStr); } this.value = value; } LocalDateTime getDateTime() { return dateTime; } } private static class TimePeriod { LocalDateTime start; LocalDateTime end; // null表示仍在持续 TimePeriod(LocalDateTime start, LocalDateTime end) { this.start = start; this.end = end; } } /** * 获取工序名称方法 * @param eid * @return */ String getProcessname(String eid) { try { return processmanageService.getInfo( equipmentledgerService.getInfo(eid).getProcesscode() ).getProcessname(); } catch (Exception e) { logger.error("获取工序名称失败: {}", e.getMessage()); return "未知工序"; } } /** * 获取设备名称方法 * @param eid * @return */ String getEquipname(String eid) { try { return equipmentledgerService.getInfo(eid).getDevicename(); } catch (Exception e) { logger.error("获取设备名称失败: {}", e.getMessage()); return "未知设备"; } } } 报警记录的结束时间的分析存在问题,报警结束时间应分析limitingValue值的条件和farBeyondValue值的条件。对每个点遍历分析limitingValue值不满足可直接返回,若limitingValue值满足farBeyondValue六个小时之内数据不满足,且不是第一桶,那要查找上一桶最后满足farBeyondValue时间,将他的下一小时返回,如果是第一桶,那返回本桶的第一个时间。
09-05
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值