思路:
a. 随机选取一个pivoty,然后利用快排思想找到其对应顺序的位置,同时在遍历的过程中计算Pivoty的重数sum。
b. 比较pivoty当前位置左边有多少数,右边有多少数,如果有小于其重数的那边不用考虑了,有大于重数的就转入这一侧继续第一步的步骤。
c. 在每一次计算出来当前的pivoty的重数时,需要比较与当前记录的最大重数大小关系,实时更新最大重数。
public class mode{
public static int maxMode=0,maxNum=0;
public static void main(String[] args) {
int nums[]=new int[20];
int min=1,max=8,n=20;
for(int i=0;i<n;i++){
nums[i]=new Random().nextInt(max-min)+min;
System.out.print(nums[i]+" ");
}
find_mode(nums,0,nums.length-1);
System.out.println("\n+众数 is:"+maxNum);
System.out.println("\n+重数 is:"+maxMode);
}
public static void find_mode(int[] nums,int left,int right){
if(left>=right) return ;
int count=1;
int key=nums[left];
int i = left, j = right;
while (i < j) {
// 在右边找到第一个比key小的值
while (i < j && nums[j] >=key ) {
j--;
if(nums[j]==key)count++;
}
nums[i] = nums[j];
// 在左边找到第一个比key大的值
while (i < j && nums[i] <= key) {
i++;
if(nums[i]==key)count++;
}
nums[j] = nums[i];
}
nums[i]=key;
if(count>maxMode){
maxNum=key;
maxMode=count;
}
if(right-i>count){
find_mode(nums,i+1,right);
}
if(i-left>count){
find_mode(nums,left,i-1);
}
}
}
public class mode{
public static void main(String[] args) {
int nums[]=new int[20];
int min=1,max=8,n=20;
for(int i=0;i<n;i++){
nums[i]=new Random().nextInt(max-min)+min;
}
modeExercise(nums);
}
public static void modeExercise(int[] nums) {
Map<Integer, Integer> recode = new HashMap<>();
for (int i = 0; i < nums.length; i++) {
if (recode.containsKey(nums[i])) {
recode.replace(nums[i], recode.get(nums[i]) + 1);
} else {
recode.put(nums[i], 1);
}
System.out.print(nums[i]+" ");
}
int maxKey=0, maxValue=0;
Iterator iter = recode.entrySet().iterator();
while (iter.hasNext()) {
Map.Entry entry = (Map.Entry) iter.next();
int key = (int) entry.getKey();
int val = (int) entry.getValue();
if(val>maxValue){
maxKey=key;
maxValue=val;
}
}
System.out.println("\n众数是:"+maxKey+"\n重数是:"+maxValue);
}
}
题目:对平面上给定的N个点,给出所有点对的最短距离即,输入是平面上的N个点,输出是N点中具有最短距离的两点
public class mode {
public static int x[],y[];
public static void main(String[] args) {
int N;
Scanner sc=new Scanner(System.in);
System.out.println("请输入N:");
N=sc.nextInt();
x=new int[N];
y=new int[N];
int recordOne=0,recordTwo=0;
System.out.println("请输入N个点对:");
for(int i=0;i<N;i++){
x[i]=sc.nextInt();
y[i]=sc.nextInt();
}
int minDist=Integer.MAX_VALUE;
for(int i=0;i<N;i++){
for(int j=i+1;j<N;j++){
int Dist= (int) (Math.pow(x[i]-x[j],2)+Math.pow(y[i]-y[j],2));
if(Dist<minDist){
recordOne=i;
recordTwo=j;
minDist=Dist;
}
}
}
System.out.println("最近的两个点为:");
System.out.print("("+x[recordOne]+","+y[recordOne]+") ");
System.out.print("("+x[recordTwo]+","+y[recordTwo]+") ");
}
}
与一维类似,二维最近点问题分治法思想也是先将这些点按照x值从小到大排序。
a.第一步:找到mid=(left+right)/2,接下来最近点要么在(leftmid)中,要么在(mid+1right)中,要么一个在左侧一个在右侧。
b.第二步:难点!!!最近点一个在左侧一个在右侧该怎么找?其实就是跟左侧、右侧最近距离的最小值d比较,找是否存在左侧和右侧距离小于d得值,如果存再必然x1值在[mid-d,mid]中间和x2在[mid,mid+d]中间,两个点的y值只差小于d
c.找到这些点后直接计算距离并更新最短距离以及点即可。
#include
#include
#include
#include
#include
using namespace std;
const double INF = 1e20;
const int N=100;
struct Point {
double x;
double y;
}point[N];
int n;
int tmpt[N];
bool cmpxy(const Point& a, const Point& b)
{
if (a.x != b.x)
return a.x < b.x;
return a.y < b.y;
}
bool cmpy(const int& a, const int& b)
{
return point[a].y < point[b].y;
}
double min(double a, double b)
{
return a < b ? a : b;
}
double dis(int i, int j)
{
return sqrt(pow((point[i].x - point[j].x),2)+pow((point[i].y - point[j].y),2));
}
double* Closest_Pair(int left, int right)
{
double d = INF;
double* index=new double[3];
if (left == right) {
index[0] = -1;
index[1] = -1;
index[2] = d;
return index;
}
if (left + 1 == right) {
index[0] = left;
index[1] = right;
index[2] = dis(left, right);
return index;
}
int mid = (left + right) /2;
double* d1 = Closest_Pair(left, mid);
double* d2 = Closest_Pair(mid + 1, right);
if (d1[2] <= d2[2]) {
index[0] = d1[0];
index[1] = d1[1];
index[2] = d1[2];
}
else {
index[0] = d2[0];
index[1] = d2[1];
index[2] = d2[2];
}
d = index[2];
int i, j, k = 0;
//分离出宽度为d的区间
for (i = left; i <= right; i++)
{
if (fabs(point[mid].x - point[i].x) <= d)
tmpt[k++] = i;
}
sort(tmpt, tmpt + k, cmpy);
//线性扫描
for (i = 0; i < k; i++)
{
for (j = i + 1; j < k && (point[tmpt[j]].y - point[tmpt[i]].y < d); j++)
{
double d3 = dis(tmpt[i], tmpt[j]);
if (d3<d) {
d = d3;
index[0]=i;
index[1]=j;
index[2]=d3;
}
}
}
return index;
}
int main()
{
while (true)
{
cout << "请输入n:";
cin >> n;
if (n == 0)
break;
for (int i = 0; i < n; i++) {
cin >> point[i].x >> point[i].y;
}
sort(point, point + n, cmpxy);
Point index[2];
double* result = Closest_Pair(0, n - 1);
cout<<"\n最近距离为:"<<result[2]<<endl;
cout << "最近的两个点为:(" << point[(int)result[0]].x << "," << point[(int)result[0]].y << ")";
cout << "、(" << point[(int)result[1]].x << ", " << point[(int)result[1]].y << ")"<<endl;
}
return 0;
}
class Solution {
public int maxSubArray(int[] nums) {
//动态规划,dp[i]为以i结尾的子序列的最大和
int a0;
a0=nums[0];
int max=a0;
for(int i=1;i<nums.length;i++){
a0=a0>0?(a0+nums[i]):nums[i];
max=Math.max(max,a0);
}
return max;
}
}
这个题目用分治法难点在于每个问题分成两个字问题后剩余的操作,也就是如果最长子序列一部分在左部,一部分在右部,那应该怎么做,此时需要遍历了,一直找,找左侧以mid开始连续最大子序列以及右侧以mid+1开始的连续最大子序列,两个之和就是maxMid,但在这里要注意left right以及right-left1时的情况,如果不简单操作会导致时间超时。
class Solution {
public int maxSubArray(int[] nums) {
//分治思想
return findMaxSubArray(nums,0,nums.length-1);
}
public int findMaxSubArray(int[] nums,int left,int right){
if(left==right) return nums[left];
if(right-left==1){
return Math.max(Math.max(nums[left],nums[right]),nums[left]+nums[right]);
}
int mid=(right-left)/2+left;
int maxLeft=findMaxSubArray(nums,left,mid);
int maxRight=findMaxSubArray(nums,mid+1,right);
int maxMid,sum;
int maxL=nums[mid];
sum=0;
for(int i=mid;i>=0;i--){
sum+=nums[i];
maxL=Math.max(maxL,sum);
}
int maxR=nums[mid+1];
sum=0;
for(int i=mid+1;i<=right;i++){
sum+=nums[i];
maxR=Math.max(maxR,sum);
}
maxMid=maxL+maxR;
return Math.max(Math.max(maxLeft,maxRight),maxMid);
}
}
给定一个序列,若该序列任意的连续子序列中都存在至少一个元素不与其他元素重复,则称该序列为不无聊序列
给定一个长度为N(N<=200000)的数列,问该数列是否为不无聊序列
主要思路:对于当前序列,如果能找到一个在i位置的字符只出现了一次,那么所有包含这个字符的连续子序列都是不无聊序列,接下来就是分治思想,去找序列[left,i-1]和[i+1,right]继续上述操作,但要注意我们需要先初始化每个字符离自己最近的相同字符,左右两边都要找。
public class mode {
public static int l[],r[];
public static void main(String[] args) {
int n;
int nums[];
Scanner sc=new Scanner(System.in);
System.out.print("请输入n:");
n=sc.nextInt();
nums=new int[n];
System.out.print("\n请输入n个数据:");
for(int i=0;i<n;i++){
nums[i]= sc.nextInt();
}
l=new int[n];
r=new int[n];
init(nums);
boolean result=solve(0,n-1);
System.out.println(result);
}
public static void init(int[] nums){
Map<Integer, Integer> map=new HashMap<>();
map.clear();
for(int i=0;i<nums.length;i++){
if(map.containsKey(nums[i])){
l[i]=map.get(nums[i]);
}else{
l[i]=-1;
}
if(map.containsKey(nums[i])) map.replace(nums[i],i);
else map.put(nums[i],i);
}
map.clear();
for(int j=nums.length-1;j>=0;j--){
if(map.containsKey(nums[j])){
r[j]=map.get(nums[j]);
}else{
r[j]=nums.length;
}
if(map.containsKey(nums[j])) map.replace(nums[j],j);
else map.put(nums[j],j);
}
}
public static boolean solve(int left,int right) {
if (left >= right) return true;
int i=left,j=right;
while(i<=j){
if(l[i] < left && r[i] > right){
return solve(left, i - 1) && solve(i + 1, right);
}
i++;
if(l[j] < left && r[j] > right){
return solve(left, j - 1) && solve(j + 1, right);
}
j--;
}
return false;
}
}