算法简单笔记3

今天5月30号,特么的昨天下午还体测,体测完塔玛的帮别人跑1000米还塔玛的被抓了,吃个处分他娘的直接没心情学了,29号塔玛得一天没学死臭咯,现在看看能写出几道题吧,还有2天时间

一、蓝桥杯不知第几届编程题:合并数列(中难)

【思路】:双指针、前缀和

(当然大家都知道java里没有指针,我这里就是用2个index代替指针的作用来找对应下标的数而已)

首先我们根据题意可以确定几点:

1、这两个数组的 "和" 一定一样

2、所有数都是正整数

3、根据前面的点我们可以确定,不管哪个数组,从左往右加都必然是【单调递增】的

4、那么最糟糕的情况 就是两个数组只能合并成一个数字,这样时两个数组的总和才一样

5、如果两个数组是一模一样 ,就不用分割合并数组

6、最后注意一下!注意一下!合并次数

两个数组任意一个合并一次都要算入合并次数里

然后注意!两种情况分别对应两种【合并次数

(1)普通情况:当可以凑成和一样 的时候,优先合并成和一样的

(2)最糟糕情况:而没有和一样的数组 的时候,就只能不断两个两个的合并,直到出现两个相同和的两个数组!!!有点抽象,看图片例子!!

当是最糟糕情况时:只能不断两个两个的合并

一般情况时:优先合并成和一样的

那么既然涉及到数组和,我第一个想到的就是前缀和(就是记录递增和的数组)

那么当我把多组数据的前缀和对比,发现一个规律:

无论什么情况,如果遍历这两个数组时,

数组a的前缀和不等于数组b前缀和的时候百分之一万要合并数组!!!!

当数组a前缀和等于数组b前缀和的时候 】,就说明已经在相同和的合并数组里了,啥也不用管只管往后遍历就行。

看下面图理解:

【数组a的前缀和不等于数组b前缀和的时候,百分之一万要合并数组】

当数组a前缀和等于数组b前缀和的时候,就说明已经在相同和的合并数组里了

那么规律简单来说就是:得出两个前缀和数组,然后两个指针分别遍历数组,前缀和一样的时候 啥也不用管、双指针同时往后遍历;前缀和不一样的时候,谁小就指针往谁后遍历(合并数组),并统计【合并次数+1】;

完整代码:

java 复制代码
import java.util.Queue;
import java.util.Scanner;

public class 国赛_合并数列 {
    public static void main(String[] args){
        Scanner in = new Scanner(System.in);
        int n = in.nextInt();
        int m = in.nextInt();
        //装两个数组,这里数组长度多+1,是为了空出第0位方便前缀和计算
        int[] a = new int[n+1];
        int[] b = new int[m+1];

        //这两个数组是前缀和数组,这里数组长度多+1,是为了空出第0位方便前缀和自己计算
        int[] a_ans = new int[n+1];
        int[] b_ans = new int[m+1];

        for (int i = 1; i < n+1; i++) {
            a[i] = in.nextInt();
            //前缀和成员等于原数组每一个成员累计加后面的成员
            a_ans[i] = a_ans[i-1]+a[i];
        }
        for (int i = 1; i < m+1; i++) {
            b[i] = in.nextInt();
            //前缀和成员等于原数组每一个成员累计加后面的成员
            b_ans[i] = b_ans[i-1]+b[i];
        }

        //index1是遍历a的前缀和数组的"指针"
        int index1 = 1;
        //index2是遍历b的前缀和数组的"指针"
        int index2 = 1;
        //count是统计【最少合并次数】的
        int count = 0;
        while (index1 < a_ans.length && index2 < b_ans.length){
            if (a_ans[index1] == b_ans[index2]) { //前缀和相同的时候就说明就在合法的合并区域内,啥也不用管,直接同时往后遍历
                index1++;
                index2++;
            } else if (a_ans[index1] < b_ans[index2]) { //前缀和不一样的话,谁小就让谁往后合并数组,并且要统计当前合并了一次数组
                count++;
                index1++;
            } else {
                count++;
                index2++;
            }
        }

        System.out.println(count);
    }
}

二、蓝桥杯不知第几届编程题:数等腰三角(史诗级顶级难)

【思路】:直角坐标系公式、排列组合、哈希表、枚举

1、思路一

首先我们遍历所有的点(x , y) ,每遍历到一个点,就以这个点为三角形的顶点 ,这个顶点到其中两个点的距离都相等 的话,就可以凑一个等腰三角形

注意!我们仅考虑以这个点为顶点来凑等腰三角形

提一下距离公式:

但是因为开根号要涉及到浮点数,那既然只是用来比较距离,d的平方也可以,那就去掉根号

2、思路二

但不是直接数有几条距离相等的边就能确定能凑出几个三角形的,这样不准、而且效率也不高,例子:

那么要知道:★一个圆内,圆心到圆弧上任意一点距离相等

那么我们就可以分类,把顶点距离相同的这些点归为一类 ,凑成 "一个圆"

然后在这个圆里,圆心与2个点可凑一个等腰三角形,几个点里两个点凑一组有几种可能?这不就是排列组合吗

3、留意点

但是还要考虑到特殊情况:三点共线

如果是三点共线 的话,即使这两个点距离圆心距离一样也不能凑成等腰三角形,普通三角形都凑不成。

那么再遍历圆弧上所有的点,每遍历到一个点(x2 , y2),根据下面这个公式,求出跟它共线的点

当求出这个跟它共线的**点(x3 , y3)**之后,运用 "哈希表" 标记这个点是个【不合法点 】,有几个【不合法点】就表示出现了几次三点共线情况

但是还要注意这两个点在一个线上,当以点(x2 , y2)求共线点时会标记点(x3 , y3)

而当以点(x3 , y3)求共线点时,又会标记点(x2 , y2) 为【不合法点

但是这就重复标记了两次这个直线三点共线的情况

所以三点共线****的情况次数 应该是【不合法点 / 2

4、总结公式

那么一个"圆"里的n个圆弧点可以凑几个三角形: - (不合法点 / 2)

那么最后以某一个点为三角形的顶点时,可以凑出几个等腰三角形就是:距离各个其他点的凑成的各个"圆"里可以凑几个三角形相加

最后一个二维坐标系里这些点可以组成几个等腰三角形:枚举所有点为顶点时可以凑几个等腰三角形,然后相加,看下面一个例子

所以最后总共可以凑4个等腰三角形

完整代码:

我自己的(我乏了,我一点做不出来,我花了整整一天时间证明了自己的智商有限,答案是错误的,希望有牛逼的大佬指出我的代码的问题所在)

java 复制代码
import java.util.*;

public class 数等腰三角形 {
    public static void main(String[] args){
        Scanner in = new Scanner(System.in);
        int n = in.nextInt();
        int[][] point = new int[n][2];
        Map<int[],Integer> Point = new HashMap<>();

        //输入所有点的坐标
        for (int i = 0; i < n; i++) {
            point[i][0] = in.nextInt();
            point[i][1] = in.nextInt();
            Point.put(new int[]{point[i][0],point[i][1]} , 1);
        }

        //哈希表记录每一个顶点(圆心)的相同距离的边的点的坐标
        Map<Integer, ArrayList<int[]>> map = new HashMap<>();

        //统计总共有多少等腰三角形
        int count = 0;

        //枚举所有点,遍历到一个,就以他为顶点(圆心)
        for (int i = 0; i < point.length; i++) {
            //获取顶点坐标
            int vertexX = point[i][0];
            int vertexY = point[i][1];

            //遍历除了顶点(圆心)以外的其他所有点
            for (int j = 0; j < point.length; j++) {
                if( i != j ){
                    //记录下当前这个外围点坐标
                    int x2 = point[j][0];
                    int y2 = point[j][1];

                    //计算距离,并记录这个距离有一条边(circlePoint数组当前下标 +1)
                    int d = (int)(Math.pow(vertexX-x2,2) + Math.pow(vertexY-y2,2));

                    //然后记录下
                    int[] circlePoint = {x2, y2};
                    ArrayList<int[]> list = map.getOrDefault(d,new ArrayList<>());
                    list.add(circlePoint);
                    map.put(d , list);
                }
            }

            //超级超级重要!!!哈希表遍历方法
            for (Map.Entry<Integer, ArrayList<int[]>> entry : map.entrySet()) {
                int key = entry.getKey(); // 获取键
                ArrayList<int[]> list = entry.getValue();
                int sum = list.size();
                count += sum * (sum-1) / 2;

                int del = 0;
                for (int j = 0; j < list.size(); j++) {
                    int x2 = list.get(j)[0];
                    int y2 = list.get(j)[1];
                    int x3 = 2 * vertexX - x2;
                    int y3 = 2 * vertexY - y2;
                    del += Point.getOrDefault(new int[]{x3, y3},0);
                }

                count -= (del / 2);
            }
            map.clear();
        }

        System.out.println(count);
    }
}

别人的C++正确代码

cpp 复制代码
#include<bits/stdc++.h>
#define int long long 
using namespace std;

signed main(){
	int n; cin >> n;
	vector<array<int,2>>a(n);

	map<pair<int,int>, int>node;

	for(int i = 0; i < n; i ++) {
		cin >> a[i][0] >> a[i][1];
		node[{a[i][0], a[i][1]}] ++;
	}
	int ans = 0;

	for(int i = 0; i < n; i ++) {
		map<int,vector<int>>st;

		for(int j = 0; j < n; j ++) {
			int dis = (a[i][0] - a[j][0]) * (a[i][0] - a[j][0]) + (a[i][1] - a[j][1]) * (a[i][1] - a[j][1]); 	
			if(dis)st[dis].push_back(j);
		}

		for(auto x: st) {
			vector<int>&no = x.second;
			int sum = no.size();
			ans += sum * (sum - 1) / 2;
			
			int del = 0;
			for(int j = 0; j < no.size(); j ++) {
				int x1 = a[i][0], y1 = a[i][1];
				int x2 = a[no[j]][0], y2 = a[no[j]][1];
				int x3 = x1 * 2 - x2, y3 = y1 * 2 - y2;
				del += (node[{x3, y3}]);
			}
			ans -= (del / 2);
		}
	}
	cout << ans << endl;
	return 0;
}

还有别人正确的java代码

cpp 复制代码
import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        List<int[]> a = new ArrayList<>();
        Map<String, Integer> node = new HashMap<>();
        for(int i = 0; i < n; i ++) {
            int x = sc.nextInt();
            int y = sc.nextInt();
            a.add(new int[]{x, y});
            String no = x + "#" + y;
            node.put(no, node.getOrDefault(no, 0) + 1);
        }
        long ans = 0;
        for(int i = 0; i < n; i ++) {
            Map<Long, List<Integer>> st = new HashMap<>();
            for(int j = 0; j < n; j ++) {
                int x1 = a.get(i)[0], y1 = a.get(i)[1];
                int x2 = a.get(j)[0], y2 = a.get(j)[1];
                long dis = (long)Math.pow(x1 - x2, 2) + (long)Math.pow(y1 - y2, 2);
                if(dis == 0)continue;
                if(st.get(dis) == null)
                    st.put(dis, new ArrayList<Integer>());
                st.get(dis).add(j);
            }
            for(Map.Entry<Long, List<Integer>> x: st.entrySet()){
                List<Integer>no = x.getValue();
                long sum = no.size();
                ans += sum * (sum - 1) / 2;
                long del = 0;
                for(int j = 0; j < no.size(); j ++) {
                    int x1 = a.get(i)[0], y1 = a.get(i)[1];
                    int x2 = a.get(no.get((j)))[0], y2 = a.get(no.get((j)))[1];
                    int x3 = x1 * 2 - x2, y3 = y1 * 2 - y2;
                    if(node.get(x3 + "#" + y3) != null)
                        del += node.get(x3 + "#" + y3);
                }
                ans -= del / 2;
            }
        }
        System.out.println(ans);
    }
}   }
}

死臭咯这下,希望尽快有人能找出我最后一题代码的问题

相关推荐
吾日三省吾码2 小时前
JVM 性能调优
java
LNTON羚通2 小时前
摄像机视频分析软件下载LiteAIServer视频智能分析平台玩手机打电话检测算法技术的实现
算法·目标检测·音视频·监控·视频监控
弗拉唐3 小时前
springBoot,mp,ssm整合案例
java·spring boot·mybatis
oi773 小时前
使用itextpdf进行pdf模版填充中文文本时部分字不显示问题
java·服务器
少说多做3434 小时前
Android 不同情况下使用 runOnUiThread
android·java
知兀4 小时前
Java的方法、基本和引用数据类型
java·笔记·黑马程序员
哭泣的眼泪4084 小时前
解析粗糙度仪在工业制造及材料科学和建筑工程领域的重要性
python·算法·django·virtualenv·pygame
蓝黑20204 小时前
IntelliJ IDEA常用快捷键
java·ide·intellij-idea
Ysjt | 深4 小时前
C++多线程编程入门教程(优质版)
java·开发语言·jvm·c++