1、输入一串数 等于某值的数的个数——hashmap的使用
我的做法,先读入这一串数,遍历一遍找出等于某个值的数的个数,超时(空间复杂度低但时间复杂度高)
正确做法,在读入这一串数的同时创建一个hanshmap key为值、value为个数,直接找出等于某个值的数的个数
import java.util.*;public class Main{ public static void main(String[]args){ Scanner in=new Scanner(System.in); while(in.hasNext()) { LinkedHashMap<Integer,ArrayList<Integer>>map=new LinkedHashMap<>(); int n=in.nextInt(); int[]a=new int[n]; for(int i=0;i<n;i++) { a[i]=in.nextInt(); if(map.containsKey(a[i])) { map.get(a[i]).add(i+1); }else { ArrayList<Integer>list=new ArrayList<Integer>(); list.add(i+1); map.put(a[i], list); } } int q=in.nextInt(); for(int i=0;i<q;i++) { int l=in.nextInt(); int r=in.nextInt(); int k=in.nextInt(); int count=0; ArrayList<Integer>list=map.get(k); if(list!=null&&list.size()!=0) { for(Integer num:list) { if(num>=l&&num<=r) count++; } } System.out.println(count); } } }}2、字符串S由小写字母构成,长度为n。定义一种操作,每次都可以挑选字符串中任意的两个相邻字母进行交换。询问在至多交换m次之后,字符串中最多有多少个连续的位置上的字母相同?——区间动态规划
要求移动后形成的最长连续子串,这个最长连续子串可能全是a或b……c。因此,这里需要枚举移动后形成的最长连续子串里面所包含的字母;
确定了里面包含的字母,就可以专注于这个字母了,也就是说其余的字母都是没有用的,把它们从序列中挖掉;然后就值剩下目标字母了,目标字母离散地分布在序列中,因此,再离散化一下,搞完之后会生成一个行的序列,之后的动态规划就在新的序列上进行。
下面的图片表达了上述过程:
现在新的序列pos看起来是合在了一起,形成了最长连续子序列,但是,形成这些连续序列所需要的操作次数是多少呢?如果操作次数大于m,那么该序列就是不满足要求的;
因此,这里面就可以得出区间动态规划了,先从小到大枚举段长,依次求得该段长的所有子序列的操作次数,并判断是否小于等于m,如果满足要求,就更新答案。
从小到大枚举段长是为了利用子问题的结果;dp[i][j]表示把pos[i]和pos[j]之间的目标字母移动到一起,形成j - i + 1长度的连续子序列所需要的操作次数;
状态转移方程:dp[i][i + len - 1] = dp[i + 1][i + len - 2] + pos[i + len - 1] - pos[i] - len + 1;,依据是|x?a|+|x?b||x?a|+|x?b|在什么时候取得最小值。用最小的移动次数把两个目标字母移动到一起的方法就是把两个目标字母都往中间靠,状态转移方程就是根据这个来的,先把pos[i + 1] ~ pos[i + len - 2]之间的目标字母移动到一起,这个移动次数就是dp[i + 1][i + len - 2],然后把两个端点pos[i]和pos[i + len -1]处的目标字母往中间靠,所需要的移动次数是pos[i + len - 1] - pos[i] - len + 1。
原文:https://www.cnblogs.com/zealousness/p/8831159.html