算法奇妙屋(四十九)-贡献法

文章目录

一. lintcode 1814 · 所有子数组之和

1. 题目解析

题意还是很好理解的, 找出所有子数组, 求出总和, 这道题在lintcode需要会员, 所以看博客写代码即可, 没必要去充值

2. 算法原理

又是一个新的算法思想, 贡献法, 巧妙地统计了一个元素在所有可能子数组出现的次数

3. 代码

java 复制代码
public class Solution {

    public int subArraySum(int[] nums) {
        int n = nums.length;
        int sum = 0;
        for (int i = 0; i < n; i++) {
            sum += nums[i] * (i + 1) * (n - i);
        }
        return sum;
    }
}

二. 力扣 907. 子数组的最小值之和

1. 题目解析

和上道题类似, 也是所有子数组, 但这里是所有子数组的最小值之和

2. 算法原理

单调栈 + 贡献法

3. 代码

这里要注意计算最终和ret的时候可能会溢出, 要先转化为long再模上mod

java 复制代码
class Solution {
    public int sumSubarrayMins(int[] arr) {
        int mod = (int)(1e9 + 7);
        int n = arr.length;
        int[] L = new int[n];
        int[] R = new int[n];
        Stack<Integer> stack = new Stack<>();
        for (int i = 0; i < n; i++) {
            // 在栈不为空的前提下, 循环去栈中找到左面第一个<=arr[i]的下标, 不满足直接弹出
            while (!stack.isEmpty() && arr[stack.peek()] > arr[i]) {
                stack.pop();
            }
            // 栈为空,l设置为-1,否则就为栈顶值
            if (stack.isEmpty()) {
                L[i] = -1;
            }else {
                L[i] = stack.peek();
            }
            // 上面i的左边界已经求完, 可以将当前下标i放入到栈中了
            stack.push(i);
        }
        // 清空栈
        stack.clear();
        for (int i = n - 1; i >= 0; i--) {
            // 在栈不为空的前提下, 循环去栈中找到右面第一个<arr[i]的下标, 不满足直接弹出
            while (!stack.isEmpty() && arr[stack.peek()] >= arr[i]) {
                stack.pop();
            }
            // 栈为空,r设置为n,否则就为栈顶值
            if (stack.isEmpty()) {
                R[i] = n;
            }else {
                R[i] = stack.peek();
            }
            // 上面i的右边界已经求完, 可以将当前下标i放入到栈中了
            stack.push(i);
        }
        // 左右边界都求完, 开始计算贡献值*arr[i]
        int ret = 0;
        for(int i = 0; i < n; i++) {
            ret = (int)((long)((long)(ret + (long)((long)(i - L[i]) * (long)(R[i] - i) * (long)arr[i]))) % mod);
        }
        return ret;
    }
}

三. AcWing 蓝桥杯 2868. 子串分值

1. 题目解析

正难则反, 逆向思考, 我们不以一段字符串来考虑, 而是考虑每个字符单次出现的子区间(子数组)个数

2. 算法原理

3. 代码

注意最终ret可能会溢出, 这里定义为long

java 复制代码
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.StringTokenizer;

public class Main {
	public static void main(String[] args) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer st = new StringTokenizer(br.readLine());
		String s = st.nextToken();
		char[] c = s.toCharArray();
		int n = c.length;
		int[] hash = new int[27];
		int[] L = new int[n];
		int[] R = new int[n];
		// 初始化
		Arrays.fill(hash, -1);
		Arrays.fill(L, -1);
		Arrays.fill(R, n);
		for (int i = 0; i < n; i++) {
			int index = c[i] - 'a';
			if (hash[index] != -1) {
				L[i] = hash[index];
			}
			hash[index] = i;
		}
		// 再次初始化
		Arrays.fill(hash, -1);
		for (int i = n - 1; i >= 0; i--) {
			int index = c[i] - 'a';
			if (index >= 0 && index <= 25 && hash[index] != -1) {
				R[i] = hash[index];
			}
			hash[index] = i;
		}
		long ret = 0;
		for (int i = 0; i < n; i++) {
			ret += (long)(i - L[i]) * (R[i] - i);
		}
		System.out.println(ret);
	}
}
相关推荐
强哥聊算力4 小时前
《算力江湖·英伟达传奇》第七集:ChatGPT出现前夜,英伟达发生了什么?
服务器·人工智能·算法·ai·chatgpt·gpu算力
哦虎!7 小时前
【JavaEE】网络初识
java
for_ever_love__7 小时前
MySQL ORDER BY 排序优化:从 Using filesort 到索引有序扫描(含双路 / 单路排序原理)
java·mysql·优化·存储·by·order·filesort
我是人✓8 小时前
Java文件上传三方式对比:从传统到SpringBoot
java·开发语言
欣栀♡8 小时前
JVM 频繁 Full GC 先看日志括号里的 cause,jstat 的 FGC 在 JDK 8 上会骗人
java·jvm
Navigator_Z8 小时前
LeetCode //C - 1289. Minimum Falling Path Sum II
c语言·算法·leetcode
CCblandy8 小时前
令牌桶在 0.9 倍负载超发 19%、固定窗口边界放行 20 个:四种限流算法同构实测
后端·python·算法·性能优化·架构
IT研究室8 小时前
最新计算机毕业设计选题推荐-基于spring boot的葡萄酒文化宣传网站-网站-文档指导-Java-springboot
java·spring boot·课程设计
慧都小项8 小时前
MyEclipse 中创建和测试 JAX-RS REST 接口:从项目配置到 REST Explorer
java·restful·myeclipse·jax-rs
Wang's Blog8 小时前
Java 项目实战: 交友项目 - 入门案例:编写 Dubbo 服务提供者
java·dubbo·交友