UvaL4513-Stammering Aliens | LCP最长公共前缀+Hash

本文介绍了解决UvaL4513-StammeringAliens问题的方法,该问题是寻找一组字符串中出现超过一半次数的最长子串。通过连接所有字符串形成母串并利用后缀数组和最长公共前缀技术来确定满足条件的子串。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

UvaL4513 - Stammering Aliens

题意:

给出n( n <= 100)个字符串, 只包含小写字母, 每个字符串长度不超过1000且不为空
求出最长的子串,满足在n个字符串当中出现在一半以上的字符串上, 如果有多个这样的子串,按字典序输出

题解:

先吐槽一波,好气哦,cmp函数+l写成了+1(follow me: yi),然后就找了一个小时的bug
这个题是要求构造一个串,跟一半的串有最长公共前缀,所以就将所有的串连起来当作母串处理
然后求出最长公共前缀,因为是要求字典序,所以求后缀数组
hight[]数组的含义就是i与i-1串的最长公共前缀的长度,如果hight[i]>=mid,那么就符合
二分搜索长度,然后判断是否符合条件
sa[]数组的含义是 第i大的串在原串中的起始位置为sa[i]
belong[]数组的含义是 第i个字符属于原串的第几组字符
vis[]数组用于判断是否已经加进记录数组pos[mid]

代码:
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <vector>

using namespace std;

const int maxn=110000;
int s[maxn],r[maxn],sa[maxn];
int t1[maxn],t2[maxn],c[maxn];
int Rank[maxn],height[maxn],belong[maxn];
int n,len;

vector<int> pos[1005];
bool vis[110];

bool cmp(int r[],int a,int b,int l)
{
    return r[a]==r[b]&&r[a+l]==r[b+l];
}

void da(int str[],int sa[],int n,int m)
{
//    n++;
    int i,j,p,*x=t1,*y=t2;
    for(i=0; i<m; ++i) c[i]=0;
    for(i=0; i<n; ++i) c[x[i]=str[i]]++;
    for(i=0; i<m; ++i) c[i]+=c[i-1];
    for(i=n-1; i>=0; --i) sa[--c[x[i]]]=i;
    for(j=1; j<=n; j<<=1)
    {
        p=0;
        for(i=n-j; i<n; ++i) y[p++]=i;
        for(i=0; i<n; ++i) if(sa[i]>=j) y[p++]=sa[i]-j;
        for(i=1; i<m; ++i) c[i]=0;
        for(i=0; i<n; ++i) c[x[y[i]]]++;
        for(i=1; i<m; ++i) c[i]+=c[i-1];
        for(i=n-1; i>=0; --i) sa[--c[x[y[i]]]]=y[i];
        swap(x,y);
        p=1;
        x[sa[0]]=0;
        for(i=1; i<n; ++i)
            x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
        if(p>=n) break;
        m=p;
    }
    int k=0;
    n--;
    for(i=0; i<=n; ++i) Rank[sa[i]]=i;
    for(i=0; i<n; ++i)
    {
        if(k) --k;
        j=sa[Rank[i]-1];
        while(str[i+k]==str[j+k]) ++k;
        height[Rank[i]]=k;
    }
}


bool solve(int mid)
{
    bool lp=false,fg=false;
    memset(vis,false,sizeof(vis));
    int cnt=0;
    for(int i=1;i<len;++i)
    {
        if(height[i]<mid)
        {
            memset(vis,false,sizeof(vis));
            vis[belong[sa[i]]]=true;
            cnt=1;
            fg=false;
        }
        else
        {
            if(!vis[belong[sa[i]]])
            {
                cnt++;
                vis[belong[sa[i]]]=true;
            }
            if(cnt>(n/2))
            {
                lp=true;
                if(!fg)
                {
                    pos[mid].push_back(sa[i]);
                    fg=true;
                }
            }
        }
    }
    return lp;
}

int main()
{
    char ss[1005];
    bool fg=false;
    while(scanf("%d",&n)&&n)
    {
        if(fg) puts("");
        len=0;
        for(int i=0; i<n; ++i)
        {
            scanf("%s",ss);
            int d=strlen(ss);
            for(int j=0;j<d;++j)
            {
                s[len]=ss[j]-'a'+1;
                belong[len]=i;
                len++;
            }
            s[len++]=27+i;
        }
        s[len-1]=0;
        da(s,sa,len,130);

        for(int i=0;i<=1000;++i) pos[i].clear();

        int l=0,r=1000,mid,ans=0;
        while(l<=r)
        {
            mid=(l+r)>>1;
            if(solve(mid))
            {
                ans=mid;
                l=mid+1;
            }
            else r=mid-1;
        }

        if(ans==0)
        {
            puts("?");
            continue;
        }
/*
        printf("---%d\n",ans);
        for(int i=0;i<pos[ans].size();++i)
            printf("%d ",pos[ans][i]);
        printf("\n");
*/


        for(int i=0;i<pos[ans].size();++i)
        {
            for(int j=0;j<ans;++j)
                printf("%c",s[pos[ans][i]+j]+'a'-1);
            printf("\n");
        }
        fg=true;
    }

    return 0;
}



package com.example.ball.ui.activity; import android.graphics.Color; import android.os.Build; import android.os.Bundle; import android.util.Log; import android.util.Size; import android.view.View; import android.widget.TextView; import androidx.annotation.NonNull; import androidx.annotation.RequiresApi; import androidx.appcompat.app.AppCompatActivity; import androidx.camera.core.CameraSelector; import androidx.camera.core.ImageAnalysis; import androidx.camera.core.ImageProxy; import androidx.camera.core.Preview; import androidx.camera.lifecycle.ProcessCameraProvider; import androidx.camera.view.PreviewView; import androidx.core.content.ContextCompat; import com.example.ball.R; import com.google.common.util.concurrent.ListenableFuture; import java.nio.ByteBuffer; import java.util.HashMap; import java.util.Map; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class CameraActivity extends AppCompatActivity { private static final String TAG = "ColorRecognition"; private static final int SAMPLE_SIZE = 5; // 采样区域半径 private static final int COLOR_TOLERANCE = 80; // 颜色匹配容差 // 预设的10种颜色及其名称 private static final Map<Integer, String> PRESET_COLORS = new HashMap<Integer, String>() {{ put(Color.RED, "红色"); put(Color.GREEN, "绿色"); put(Color.BLUE, "蓝色"); put(Color.YELLOW, "黄色"); put(Color.CYAN, "青色"); put(Color.MAGENTA, "品红"); put(0xFFFFA500, "橙色"); // 橙色 put(0xFF800080, "紫色"); // 紫色 put(0xFFFFC0CB, "粉色"); // 粉色 put(0xFFA52A2A, "棕色"); // 棕色 }}; private PreviewView previewView; private View targetArea; private View colorPreview; private TextView tvColorName; private TextView tvColorInfo; private TextView tvDetectionStatus; private ExecutorService cameraExecutor; private int targetX = 0; // 目标区域中心X坐标 private int targetY = 0; // 目标区域中心Y坐标 @RequiresApi(api = Build.VERSION_CODES.M) @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_camera); previewView = findViewById(R.id.previewView); targetArea = findViewById(R.id.targetArea); colorPreview = findViewById(R.id.colorPreview); tvColorName = findViewById(R.id.tvColorName); tvColorInfo = findViewById(R.id.tvColorInfo); tvDetectionStatus = findViewById(R.id.tvDetectionStatus); cameraExecutor = Executors.newSingleThreadExecutor(); // 设置目标区域位置(屏幕中心) previewView.post(() -> { targetX = previewView.getWidth() / 2; targetY = previewView.getHeight() / 2; updateTargetPosition(); }); // 启动摄像头 if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.CAMERA) == android.content.pm.PackageManager.PERMISSION_GRANTED) { startCamera(); } else { requestPermissions(new String[]{android.Manifest.permission.CAMERA}, 1); } } private void updateTargetPosition() { targetArea.setX(targetX - targetArea.getWidth() / 2f); targetArea.setY(targetY - targetArea.getHeight() / 2f); } private void startCamera() { ListenableFuture<ProcessCameraProvider> cameraProviderFuture = ProcessCameraProvider.getInstance(this); cameraProviderFuture.addListener(() -> { try { ProcessCameraProvider cameraProvider = cameraProviderFuture.get(); // 配置预览 Preview preview = new Preview.Builder().build(); preview.setSurfaceProvider(previewView.getSurfaceProvider()); // 配置图像分析 ImageAnalysis imageAnalysis = new ImageAnalysis.Builder() .setTargetResolution(new Size(640, 480)) // 优化性能 .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST) .build(); imageAnalysis.setAnalyzer(cameraExecutor, new ColorAnalyzer()); // 选择后置摄像头 CameraSelector cameraSelector = new CameraSelector.Builder() .requireLensFacing(CameraSelector.LENS_FACING_BACK) .build(); // 绑定用例 cameraProvider.bindToLifecycle(this, cameraSelector, preview, imageAnalysis); } catch (ExecutionException | InterruptedException e) { Log.e(TAG, "Camera setup error: " + e.getMessage()); } }, ContextCompat.getMainExecutor(this)); } private class ColorAnalyzer implements ImageAnalysis.Analyzer { @Override public void analyze(@NonNull ImageProxy image) { // 坐标转换(预览坐标 → 图像坐标) int imgWidth = image.getWidth(); int imgHeight = image.getHeight(); int previewWidth = previewView.getWidth(); int previewHeight = previewView.getHeight(); int imgX = (int) (targetX * (imgWidth / (float) previewWidth)); int imgY = (int) (targetY * (imgHeight / (float) previewHeight)); // 从YUV数据提取颜色 int color = extractColor(image, imgX, imgY); // 更新UI runOnUiThread(() -> updateColorDisplay(color)); image.close(); } private int extractColor(ImageProxy image, int centerX, int centerY) { ImageProxy.PlaneProxy[] planes = image.getPlanes(); int rSum = 0, gSum = 0, bSum = 0; int count = 0; // 采样区域:中心点周围5x5像素 for (int dy = -SAMPLE_SIZE; dy <= SAMPLE_SIZE; dy++) { for (int dx = -SAMPLE_SIZE; dx <= SAMPLE_SIZE; dx++) { int x = centerX + dx; int y = centerY + dy; if (x >= 0 && x < image.getWidth() && y >= 0 && y < image.getHeight()) { int color = getRGBFromYUV(planes, x, y, image.getWidth()); rSum += Color.red(color); gSum += Color.green(color); bSum += Color.blue(color); count++; } } } // 计算平均颜色 if (count > 0) { return Color.rgb(rSum / count, gSum / count, bSum / count); } return Color.BLACK; } // 高效YUV转RGB private int getRGBFromYUV(ImageProxy.PlaneProxy[] planes, int x, int y, int width) { ByteBuffer yBuffer = planes[0].getBuffer(); ByteBuffer uBuffer = planes[1].getBuffer(); ByteBuffer vBuffer = planes[2].getBuffer(); // 计算偏移量 int yOffset = y * planes[0].getRowStride() + x * planes[0].getPixelStride(); int uvX = x / 2; int uvY = y / 2; int uOffset = uvY * planes[1].getRowStride() + uvX * planes[1].getPixelStride(); int vOffset = uvY * planes[2].getRowStride() + uvX * planes[2].getPixelStride(); // 获取YUV值 int yVal = yBuffer.get(yOffset) & 0xFF; int uVal = uBuffer.get(uOffset) & 0xFF; int vVal = vBuffer.get(vOffset) & 0xFF; // YUV转RGB公式 int r = clamp((int) (yVal + 1.402 * (vVal - 128))); int g = clamp((int) (yVal - 0.34414 * (uVal - 128) - 0.71414 * (vVal - 128))); int b = clamp((int) (yVal + 1.772 * (uVal - 128))); return Color.rgb(r, g, b); } private int clamp(int value) { return Math.max(0, Math.min(255, value)); } } private void updateColorDisplay(int detectedColor) { // 更新颜色预览 colorPreview.setBackgroundColor(detectedColor); // 获取RGB值 int r = Color.red(detectedColor); int g = Color.green(detectedColor); int b = Color.blue(detectedColor); String rgb = String.format("RGB: %d, %d, %d", r, g, b); tvColorInfo.setText(rgb); // 匹配预设颜色 String colorName = "未设定颜色"; for (Map.Entry<Integer, String> entry : PRESET_COLORS.entrySet()) { int presetColor = entry.getKey(); int pr = Color.red(presetColor); int pg = Color.green(presetColor); int pb = Color.blue(presetColor); // 计算颜色距离 double distance = Math.sqrt( Math.pow(r - pr, 2) + Math.pow(g - pg, 2) + Math.pow(b - pb, 2) ); if (distance < COLOR_TOLERANCE) { colorName = entry.getValue(); break; } } tvColorName.setText(colorName); tvDetectionStatus.setText(colorName.equals("未设定颜色") ? "识别区域" : "检测到: " + colorName); } @Override protected void onDestroy() { super.onDestroy(); if (cameraExecutor != null) { cameraExecutor.shutdown(); } } } 以上预设的颜色由于识别不够精准导致与需求不符,请改成预设颜色范围
08-03
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值