distinct sequence Google

本文介绍了一种使用动态规划解决LeetCode上子序列计数问题的方法,并对比了暴力解法。通过递归与动态规划两种方式,展示了如何计算一个字符串作为另一个字符串子序列的出现次数。

leetcode ,暴力解法dfs, 双指针,不行

    public int numDistinct(String s, String t) {
        return numDistinctHelper(s,t,0,0);
    }
    public int numDistinctHelper(String s, String t, int si, int ti){
        if(ti == t.length()) {
            return 1;
        }
        if(si >= s.length()){
            return 0;
        }
        int count = 0;
        for(int i = si; i < s.length(); i++){
            if(s.charAt(i) == t.charAt(ti)){
                count += numDistinctHelper(s,  t, i+1, ti+1);
            }
        }
        return count;
    }

A Clever way to solve it: (Dynamic Programming)
solution: Let W(i, j) stand for the number of subsequences of S(0, i) equals to T(0, j). If S.charAt(i) == T.charAt(j), W(i, j) = W(i-1, j-1) + W(i-1,j); Otherwise, W(i, j) = W(i-1,j).

    public int numDistinct(String S, String T) {
            int[][] table = new int[S.length() + 1][T.length() + 1];

            for (int i = 0; i < S.length(); i++)
                table[i][0] = 1;

            for (int i = 1; i <= S.length(); i++) {
                for (int j = 1; j <= T.length(); j++) {
                    if (S.charAt(i - 1) == T.charAt(j - 1)) {
                        table[i][j] += table[i - 1][j] + table[i - 1][j - 1];
                    } else {
                        table[i][j] += table[i - 1][j];
                    }
                }
            }

            return table[S.length()][T.length()];
    }
”// ====== 1. 加载研究区域和采样点数据 ====== var aoi = ee.FeatureCollection('projects/ee-yixuwei610/assets/hubei'); var samplePoints = ee.FeatureCollection('projects/ee-yixuwei610/assets/sample_points'); // 替换为您的采样点路径 var geometry = aoi.geometry(); Map.centerObject(geometry, 8); Map.addLayer(geometry, {color: 'red'}, 'Hubei AOI'); Map.addLayer(samplePoints, {color: 'blue'}, '采样点'); // ====== 2. 加载和处理Sentinel-2影像集 ====== var startYear = 2023; // 物候分析的年份 var startDate = ee.Date.fromYMD(startYear, 1, 1); var endDate = ee.Date.fromYMD(startYear, 12, 31); // NDVI计算函数[^4][^5] var calculateNDVI = function(image) { var ndvi = image.normalizedDifference(['B8', 'B4']).rename('NDVI'); return image.addBands(ndvi); }; // 云掩膜函数 var cloudMask = function(image) { var qa = image.select('QA60'); var cloudBitMask = 1 << 10; var cirrusBitMask = 1 << 11; var mask = qa.bitwiseAnd(cloudBitMask).eq(0) .and(qa.bitwiseAnd(cirrusBitMask).eq(0)); return image.updateMask(mask); }; // 加载Sentinel-2数据 var s2Collection = ee.ImageCollection('COPERNICUS/S2_SR') .filterBounds(geometry) .filterDate(startDate, endDate) .map(cloudMask) .map(calculateNDVI) .select('NDVI'); // ====== 3. Savitzky-Golay滤波函数[^2] ====== var applySGFilter = function(collection) { return collection.map(function(image) { // 创建周围5天的滑动窗口 var window = collection.filter(ee.Filter.inList('system:time_start', ee.List([image.get('system:time_start')]) .map(function(t) { return ee.Date(t).advance(-2, 'day').millis(); }, ee.List.sequence(-2, 2)) .flatten() )); // 应用二次多项式拟合 var sgFiltered = window.reduce(ee.Reducer.mean()); return sgFiltered.copyProperties(image, ['system:time_start']); }); }; var filteredCollection = applySGFilter(s2Collection); // ====== 4. 创建物候曲线面板组件 ====== var mainPanel = ui.Panel({ style: { position: 'bottom-right', width: '450px', padding: '10px', backgroundColor: '#f8f9fa' } }); var title = ui.Label({ value: `${startYear}年采样点物候特征曲线`, style: {fontSize: '18px', fontWeight: 'bold', margin: '0 0 10px 0'} }); mainPanel.add(title); var pointSelector = ui.Select({ items: [], placeholder: '选择采样点', style: {width: '100%', margin: '0 0 10px 0'} }); mainPanel.add(pointSelector); var chartPanel = ui.Panel({ style: {height: '300px', backgroundColor: 'white'} }); mainPanel.add(chartPanel); var phenoParams = ui.Label({ value: '等待选择采样点...', style: {margin: '10px 0 0 0', fontSize: '14px'} }); mainPanel.add(phenoParams); Map.add(mainPanel); // ====== 5. 初始化采样点列表 ====== var pointNames = samplePoints.aggregate_array('name').distinct(); pointNames.evaluate(function(names) { names.forEach(function(name) { pointSelector.items().push(name, name); }); }); // ====== 6. 时间序列拟合与物候参数计算 ====== pointSelector.onChange(function(selectedName) { var selectedPoint = samplePoints.filter(ee.Filter.eq('name', selectedName)).first(); var pointGeometry = selectedPoint.geometry(); Map.centerObject(pointGeometry, 12); Map.layers().reset([Map.layers().get(0), Map.layers().get(1)]); Map.addLayer(pointGeometry, {color: 'red', pointSize: 10}, '选中点'); // 提取原始NDVI时间序列 var rawTS = s2Collection.map(function(image) { var value = image.reduceRegion({ reducer: ee.Reducer.mean(), geometry: pointGeometry, scale: 10 }).get('NDVI'); return ee.Feature(null, { date: image.date().format('YYYY-MM-dd'), NDVI: ee.Number(value), timestamp: image.get('system:time_start'), type: '原始值' }); }); // 提取滤波后NDVI时间序列 var filteredTS = filteredCollection.map(function(image) { var value = image.reduceRegion({ reducer: ee.Reducer.mean(), geometry: pointGeometry, scale: 10 }).get('NDVI'); return ee.Feature(null, { date: image.date().format('YYYY-MM-dd'), NDVI: ee.Number(value), timestamp: image.get('system:time_start'), type: 'S-G滤波' }); }); // 合并两个时间序列 var combinedTS = rawTS.merge(filteredTS); // 创建双线图表 var chart = ui.Chart.feature.groups({ features: combinedTS, xProperty: 'timestamp', yProperty: 'NDVI', seriesProperty: 'type' }) .setChartType('LineChart') .setOptions({ title: `${selectedName} - ${startYear}年物候曲线`, hAxis: {title: '日期', format: 'MMM', gridlines: {count: 12}}, vAxis: {title: 'NDVI', minValue: -0.2, maxValue: 1.0}, lineWidth: 2, pointSize: 3, series: { 0: {color: '#4CAF50', lineWidth: 1, pointSize: 3}, // 原始值 1: {color: '#FF5722', lineWidth: 3, pointSize: 0} // S-G滤波 }, curveType: 'function' }); // 更新图表 chartPanel.widgets().reset([chart]); // 计算关键物候参数(基于滤波后数据) var phenoStats = filteredTS.aggregate_array('NDVI') .map(function(ndvi) { return ee.Number(ndvi); }); var minNDVI = phenoStats.reduce(ee.Reducer.min()); var maxNDVI = phenoStats.reduce(ee.Reducer.max()); var amplitude = maxNDVI.subtract(minNDVI); // 计算生长季开始日期(阈值法)[^1] var sosFeature = filteredTS.filter(ee.Filter.gt('NDVI', 0.3)) .limit(1, 'timestamp', false) .first(); // 更新物候参数显示 sosFeature.get('date').evaluate(function(date) { phenoParams.setValue( `NDVI振幅: ${amplitude.getInfo().toFixed(3)}\n` + `生长季开始: ${date}\n` + `NDVI峰值: ${maxNDVI.getInfo().toFixed(3)}` ); }); }); // 初始选择第一个点 if (pointSelector.items().length > 0) { pointSelector.setValue(pointSelector.items().get(0).value); } “显示所有采样点的物候特征曲线
09-01
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值