此题可以先思考暴力解法,即用三层for循环去解
for (int i = 0; i < n; i++){ // 枚举左端点
for (int j = i; j < n; j++){ // 枚举右端点
for (int k = 0; k < n; k++){
//得到区间[i,j]
对区间进行排序,排序后在挨个检查是否后一个数比前一个数严格+1
}
}
}
观察题目可以知道,区间最大值-区间最小值一定满足 关系 a[j] - a[i] == j - i;
因为最小到最大差距为 i - j + 1
import java.util.*;
class Main{
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
int N = 10010;
int[] a = new int[N];
int n = sc.nextInt();
for (int i = 0; i < n; i++){
a[i] = sc.nextInt();
}
int res = 0;
// 枚举左端点
for (int i = 0; i < n; i++){
int max = -1;
int min = 10001;
// 枚举右端点
for (int j = i; j < n; j++){
min = Math.min(min,a[j]);
max = Math.max(max,a[j]);
if (max - min == (j - i)){
res++;
}
}
}
System.out.print(res);
}
}
从暴力思维出发,此题最容易想到的做法就是用三层for循环去枚举,就不说了
两个方法:前缀和和二分法
前缀和的思路是 先把a[i] 和 c[i]出现的次数去统计,s[i] 表示 前i个数出现的总和
import java.util.*;
class Main{
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
int N = 100010;
int[] a = new int[N]; // 存放A数组
int[] b = new int[N]; // 同理
int[] c = new int[N];
int[] as = new int[N]; // as[i] 表示 有多少个数小于 b[i]
int[] cs = new int[N]; // cs[i] 表示 有多少个数大于 b[i];
int[] cnt = new int[N]; // 统计 a[i] 和 c[i] 出现的个数
int[] s = new int[N]; // 前缀和数组
int n = sc.nextInt();
for (int i = 0; i < n; i++) a[i] = sc.nextInt();
for (int i = 0; i < n; i++) b[i] = sc.nextInt();
for (int i = 0; i < n; i++) c[i] = sc.nextInt();
for (int i = 0; i < n; i++){
a[i]++;
b[i]++;
c[i]++;
// 将数字脱离0,方便前缀和计算
}
// 计算as
for (int i = 0; i < n; i++) cnt[a[i]]++;
for (int i = 1; i < N; i++) s[i] = s[i-1] + cnt[i];
for (int i = 0; i < n; i++) as[i] = s[b[i] - 1]; // 表示有多少个数比b【i】小
// 计算cs
cnt = new int[N];
s = new int[N];
for (int i = 0; i < n; i++) cnt[c[i]]++;
for (int i = 1; i < N; i++) s[i] = s[i-1] + cnt[i];
for (int i = 0; i < n; i++) cs[i] = s[N-1] - s[b[i]]; // 表示有多少个数比b【i】大
long res = 0;
for (int i = 0; i < n; i++){
res += ((long)as[i] * (long)cs[i]);
}
System.out.print(res);
}
}
二分法:
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int[] a = new int[n]; // 存放A数组
int[] b = new int[n]; // 同理
int[] c = new int[n];
for (int i = 0; i < n; i++) a[i] = sc.nextInt();
for (int i = 0; i < n; i++) b[i] = sc.nextInt();
for (int i = 0; i < n; i++) c[i] = sc.nextInt();
Arrays.sort(a);
Arrays.sort(c);
Arrays.sort(b);
int left;
int right;
long res = 0;
int as = 0;
int cs = 0;
for (int i = 0; i < n; i++){
int bi = b[i];
left = 0;
right = n - 1;
while (left < right){
int mid = (left + (right + 1)) / 2;
if (a[mid] < bi) left = mid;
else right = mid - 1;
}
as = a[left] < bi ? left : -1;
left = 0;
right = n - 1;
while (left < right){
int mid = (left + right) / 2;
if (c[mid] > bi) right = mid;
else left = mid + 1;
}
cs = c[left] > bi ? left : -1;
if (as != -1 && cs != -1){
res += ( (as + 1) * (n - cs));
}
}
System.out.println(res);
}
1、通过对输入的编号进行排序
2、从小到大遍历
(1)由于重号只会出现一个,因此当a[i] == a[i - 1]时,a[i]表示重号
(2)由于断号只会出现一个,因此一定会空缺一个数,则当a[i] == a[i - 1] + 2时,a[i] - 1表示断号
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
public class Main {
static int[] a = new int[100010];
static int k = 0;
public static void main(String[] args) throws IOException{
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
int n = Integer.parseInt(reader.readLine().trim());
while(n -- > 0)
{
String[] s1 = reader.readLine().split(" ");
for(int i = 0;i < s1.length;i++)
{
a[k ++] = Integer.parseInt(s1[i]);
}
}
Arrays.sort(a,0,k);
int res1 = -1;//断号(只会断一次)
int res2 = -1;//重号
for(int i = 1;i < k;i++)
{
if(a[i] == a[i - 1]) res2 = a[i];//重号
else if(a[i] == a[i - 1] + 2) res1 = a[i] - 1;//断号
}
System.out.println(res1 + " " + res2);
}
}
暴力思路:枚举10000000 -》 99999999 间的数字去判断日期合法并回文
解题思路:
1.先写回文
2.判断日期在给定日期之间
3.判断是否为合法日期
import java.util.*;
class Main{
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int date1 = sc.nextInt();
int date2 = sc.nextInt();
int res = 0;
for (int i = 1000; i < 10000; i++) {
int date = i;
int x = i;
for (int j = 0; j < 4; j++) {
date = date * 10 + x % 10;
x /= 10;
}
if (date1 <= date && date <= date2 && check(date)) res++;
}
System.out.println(res);
}
static int[] days = {0,31,28,31,30,31,30,31,31,30,31,30,31};
public static boolean check(int date){
int year = date / 10000;
int month = date % 10000 / 100;
int day = date % 100;
if (month == 0 || month > 12) return false;
if (day == 0 || (month != 2 && day > days[month])) return false;
if (month == 2){
if ((year % 100 != 0 && year % 4 == 0) || year % 400 == 0){
if (day > 29) return false;
}
}
return true;
}
}
最短移动距离 = 曼哈顿距离
将奇数行的数据翻转:w - 1 - y1
import java.util.*;
class Main{
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
int w = sc.nextInt();
int m = sc.nextInt();
int n = sc.nextInt();
n--;
m--;
int x1 = m / w;
int y1 = m % w;
int x2 = n / w;
int y2 = n % w;
if (x1 % 2 != 0) y1 = w - 1 - y1;
if (x2 % 2 != 0) y2 = w - 1 - y2;
System.out.print(Math.abs(x1-x2) + Math.abs(y1-y2));
}
}
m--和n--是因为借鉴了正常的数组的表示方式,从下标0开始。即可以推出行号 = n / w;
列号也是一样。
1.枚举8位数
2.判断是否为合法日期
3.判断是否满足条件
import java.util.*;
import java.io.*;
class Main{
public static void main(String[] args) throws IOException {
BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
String[] arr = bf.readLine().split("/");
// arr : a/b/c
// a/b/c || c/a/b || c/b/a
int a = Integer.parseInt(arr[0]);
int b = Integer.parseInt(arr[1]);
int c = Integer.parseInt(arr[2]);
for (int date = 19600101; date <= 20591231; date++) {
int year = date / 10000;
int month = date % 10000 / 100;
int day = date % 100;
if (check(year,month,day)){
if ( (year % 100 == a && month == b && day == c) || (year % 100 == c && month == a && day == b) || (year % 100 == c && month == b && day == a) ){
System.out.printf("%d-%02d-%02d",year,month,day);
System.out.println();
}
}
}
}
static int[] days = {0,31,28,31,30,31,30,31,31,30,31,30,31};
public static boolean check(int year,int month,int day){
if (day <= 0 || month > 12) return false;
if (month != 2 && (day > days[month])) return false;
if (month == 2){
if ((year % 100 != 0 && year % 4 == 0) || year % 400 == 0){
if (day > 29) return false;
}else {
if (day > 28) return false;
}
}
return true;
}
}
printf中 "%02d"表示不足2位时补0
有时间time:
hour = time / 3600
min = time % 3600 / 60
second = time % 60