首页 > 试题广场 >

最后一个字符

[编程题]最后一个字符
  • 热度指数:11378 时间限制:C/C++ 2秒,其他语言4秒 空间限制:C/C++ 32M,其他语言64M
  • 算法知识视频讲解
正在挑战一个CrackMe的你,把需要填写的前面几位密码都正确猜出了,可是这最后一位密码,好像藏得有点深。CrackMe的作者还挑衅般的在里面藏了个.tar.gz文件,解压缩出来,里面写道 你要的最后一个字符就在下面这个字符串里,这个字符是下面整个字符串中第一个只出现一次的字符。(比如,串是abaccdeff,那么正确字符就是b了) 然而下面给出来的字符串好像太长太长了,单靠人力完全无法找出来。 于是,你需要写一个程序代劳了。输入文件体积较大,请使用一些快速的输入输出手段,不推荐使用cin/cout,对Java并不推荐使用Scanner直接读写。

输入描述:
第一行,一个正整数T(T≤20)  ,表示输入数据组数。
之后T行,每行一个字符串S。( 1≤S 的长度≤1000000 ,保证字符串中出现的字符的ASCII码在[0x21,0x7F)范围内,即均为可显示的非空白符,同时保证一定有解)


输出描述:
一共T 行,每行一个字符C ,表示所给的相应字符串中第一个只出现一次的字符。
示例1

输入

2
abaccdeff
testonline

输出

b
s
首先,既然不推荐用cin,cout那就printf scanf吧,刚把360的2个题都看了,2个都是做下统计得到答案的。。感觉比较水啊.
O(n)的复杂度,我们开个数组统计每个字符出现的次数即可,同时统计的过程中用个队列来存储扫描到当前字符为止,第一次出现的字符(也就是最多存储93个字符而已),之后把队列元素一一弹出,输出第一个统计数为1的字符即可,代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <queue>
#include <string.h>
using namespace std;
 
int main(int arg0,char**arg1){
    int T;
    int len;
    int i;
    char temp;
    int count[93+1];
    char str[1000000+1];
    scanf("%d",&T);
    while(T-->0){
        scanf("%s",str);
        len=strlen(str);
        memset(count,0,sizeof(count));
       queue<char> qu;
        for(i=0;i<len;i++)
        {
           count[str[i]-0x21]++;
           if((count[str[i]-0x21])==1)
               qu.push(str[i]);
        }
        while(!qu.empty()){
            temp=qu.front();
            if(count[temp-0x21]==1)
                {
                printf("%c\n",temp);
                break;
            }
            qu.pop();
        }
    }
    return 0;
}
发表于 2015-09-04 00:18:27 回复(1)

python solution

时间复杂度为O(n)。使用defaultdict, 扫描两遍。第一遍,计算每个字母出现的次数。第二遍,遍历字符串,在第一个count为2的地方打断,直接输出这个数即可。

from collections import defaultdict

num = int(input())
for _ in range(num):
    a, dd = input(), defaultdict(int)
    for i in a:
        dd[i] += 1

    for i in a:
        dd[i] += 1
        if dd[i] == 2:
            print(i)
            break
发表于 2017-11-07 18:31:27 回复(0)
//这题目简单
//构建一个大数组来进行映射就解决了
//毫无争议
#include<string>
#include<stdlib.h>
#include<string.h>
#include<iostream>
using namespace std;
int a[200]={0};
int main(){
    int n;
    while(cin>>n)
    {
        for(int x=0;x<n;x++){
            string s;
            cin>>s;
            int len=s.size();
            memset(a,0,sizeof(a));
            for(int i=0;i<len;i++){
                a[s[i]]++;
            }
            for(int i=0;i<len;i++){
                if(a[s[i]]==1){
                    cout<<s[i]<<endl;
                    break;
                }
            }
    }
        
    }
    return 0;
}
发表于 2016-07-23 16:23:41 回复(1)
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.HashSet;
import java.util.LinkedHashSet;

public class CrackMe {
	private static BufferedReader in=new BufferedReader(new InputStreamReader(System.in));
	private static String t;
	static{
		try {
			t=in.readLine();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	public static void main(String[] args) {
		int T=Integer.parseInt(t);
		char[] result=new char[T];
		for(int i=0;i<T;i++){
			try {
				result[i]=findFirstUnique(in.readLine());
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		for(char a:result){
			System.out.println(a);
		}
	}
	private static char findFirstUnique(String string) {
		 char[] chars=string.toCharArray();
          HashSet<Character> doorSet=new HashSet<Character>();
          LinkedHashSet<Character> resultSet=new LinkedHashSet<Character>();
          char c;
          for(int i=0;i<chars.length;i++){
              c=chars[i];
              if(!doorSet.contains(c)){
                  if(!resultSet.add(c)){
                      resultSet.remove(c);
                      doorSet.add(c);
                  }
              }
          }
		return resultSet.iterator().next();
	}
}


发表于 2015-09-04 21:48:38 回复(1)
import java.io.*;
import java.util.*;

public class Main {
	public static void main(String[] args) {
		// 使用字符流输入
		BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
		try {
			int n = Integer.parseInt(reader.readLine());
			for (int i = 0; i < n; i++) {
				String str = reader.readLine();
				System.out.println(serch(str));
			}
		} catch (NumberFormatException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	public static char serch(String str) {
		// 只出现一次的字符记录组
		ArrayList<Character> one = new ArrayList<>();
		// 不止出现一次的记录set
		HashSet<Character> set = new HashSet<>();
		for (char c : str.toCharArray()) {
			if (!set.contains(c)) {// 不是出现多次的
				if (!one.contains(c)) {// 不存在与字符组中
					one.add(c);// 入列
				} else {// 存在字符组中
					one.remove(one.indexOf(c));// 出列
					set.add(c);// 入回收记录set
				}
			}
		}
		if (one.size() > 0) {// 存在只出现一次的,输出第一个
			return one.get(0);
		}
		return '\0';
	}
}

发表于 2020-06-04 09:36:25 回复(0)
  • 解答思路就是 读入字符,如果出现过多次就标记为-1;出现过一次的 按照出现顺序先后标记一个整数。 输出时查找最先出现的只出现一次的字符。即使字符串长度是1e9也不会溢出(hiahia)。
  • 下面贴代码,注意不要使用fflush方法,因为它本地测是没问题的,在线就挂了,太坑了(趴)。
  • 测试如果是错误答案,评测结果会提示你上一个样例的输入,和出错的样例的正确输出(?!)。
#include <cstdio>
void init(int *ct){
for(int i=0x21;i<0x7f-1;++i){
ct[i]=0;
}
};

int main(){
//init
int ct[0x7f];
int n;
int ser;
int *r;
int t;
scanf("%d",&n);
getchar();
//fflush(stdin);
while(n--){
init(ct);
ser=1;
do{
t=getchar();
//putchar(t);
//printf("%d\n",t);
//++ct[t];
ct[t]=ct[t]?-1:ser++;
}while(t>=0x21);
//fflush(stdin);

int *res=ct;
int min=0xff;
for(r=ct+0x21;r-ct<0x7f-1;++r){
if(*r>0 && *r < min){
min=*r;
res=r;
}
}
printf("%c\n",res-ct);
}
}


编辑于 2018-08-01 18:00:22 回复(0)
#include <bits/stdc++.h>

using namespace std;

int main()
{     int T;     cin>>T;     while(T--)     {         int c[150] = {0};         char s[1000010];         cin>>s;         for(int i=0;i<strlen(s);i++)             c[s[i]]++;         for(int i=0;i<strlen(s);i++)             if(c[s[i]]==1)             {                 cout<<s[i]<<endl;                 break;             }     }     return 0;
} 

发表于 2017-11-23 13:05:31 回复(0)

利用桶排序的原理。

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
struct node{
    int val;
    int first;
};
int main(){
    int n;
    scanf("%d",&n);
    int pos;
    while(n--){
        char a[1000001];
        node b[95] ;
        for(int i = 0; i < 95; i++){
            b[i].val = 0;
            b[i].first = -1;
        }
        scanf("%s",a);
        for(int i = 0; i < strlen(a); i++){
            pos = ((int)a[i])-33;
            (b[pos].val)++;
            if(b[pos].first == -1) b[pos].first = i;
        }
        int minpos = 100000000;
        for(int i = 0; i < 94; i++){
            if(b[i].val == 1 && b[i].first != -1){
                if(b[i].first < minpos) minpos = b[i].first;
            }
        }
        //printf("%d",minpos);
        printf("%c\n",a[minpos]);
    }
    return 0;
}
发表于 2017-11-06 14:10:03 回复(0)

PHP 的来一发

<?php
$n = trim(fgets(STDIN));
$arr = [];
for($i=0; $i<$n; $i++){
    $arr[] = trim(fgets(STDIN));
}
$r = [];
for($j=0; $j<$n; $j++){
    $res = [];
    for($m=0; $m<strlen($arr[$j]); $m++){
        if(array_key_exists($arr[$j][$m], $res)){
            $res[$arr[$j][$m]]++;
        }else{
            $res[$arr[$j][$m]]=1;
        }
    }
    foreach($res as $k=>$v){
        if($v==1){
            $r[]=$k;
            break;
        }
    }
}

foreach($r as $v){
    echo $v.PHP_EOL;
}
发表于 2017-09-09 16:10:34 回复(0)
程序员面试宝典上的题目
发表于 2017-01-02 10:56:04 回复(0)
#include <stdio.h>
#include <string>
#include <iostream>
#include <map>
using namespace std;

int main()
{
	int n;
	while(cin>>n)
	{
		string str;
		while(n--)
		{
			cin>>str;
			map<char,pair<int,int>> mymap;
			for(int i=0;i<str.size();i++)
			{
				if(mymap.count(str[i]))mymap[str[i]].first++;
				else mymap.insert(make_pair(str[i],make_pair(1,i)));
			}
		
			int index = str.size();
			char ans;
			for(auto it:mymap)
			{
				if(it.second.first == 1&& it.second.second<index){ans = it.first;index = it.second.second;}
			}
			cout<<ans<<endl;
		}
	}
	return 0;
}

发表于 2016-08-25 17:50:09 回复(0)
#include<iostream>
#include<vector>
using namespace std;

int main()
    {
    
    vector<int>a(100,0);
    
    int T;
    cin>>T;
    for(int i=0;i<T;i++)
        {
        for(auto& p:a)
            p=0;
       vector<char>b;
        char ch;
        if(i==0)
        ch=getchar();
       
        while((ch=getchar())!='\n')
                {
                if(a[ch-33]==0)
                    b.push_back(ch);
                a[ch-33]++;  
            }
        for(auto i=b.begin();i!=b.end();i++)
            if(a[*i-33]==1)
            {
            cout<<*i<<endl;
            break;
        }
        
        
    }
    
    return 0;
}

发表于 2016-06-01 10:05:30 回复(0)
用字典很容易实现

import sys
n=int(sys.stdin.readline().strip())
for i in range(n):
    line=sys.stdin.readline().strip()
    d={}
    for i in line:
        if d.has_key(i):
            d[i]+=1
        else:
            d[i]=1
    for i in line:
        if d[i]==1:
            print i
            break

发表于 2015-09-16 10:52:34 回复(0)
     用一个数组int  num[128]存储每一个字符出现的次数,例如num[i]表示i作为ASCII码对应的字符出现的次数,用一个vector<char> chuxian记录出现的字符,当当前字符是第一次出现时,将其存入容器,chuxian[i]表示第i+1个出现的字符。遍历字符串,将当前字符出现的次数加1,若加一以后其出现次数为1,表示是第一次出现,存入容器,否则读入下一个字符。遍历完成后,依次检查chuxian中的每一个字符,若他的出现次数为1,即找到第一个只出现一次的字符。

int main()
{
    char ch;
    int num[128];                     //存储下标对应的字符出现的次数
    int T;                               
    vector<char> chuxian;      //按顺序存储第一次出现的字符
    vector<char> out;         //应输出的字符
    scanf_s("%d",&T);
    for(int i=0;i<T;i++){                 //表示有几组数据
        chuxian.clear();
        memset(num,0,sizeof(num));              //有多组数据,所以每一次分析都要清零
    while(cin>>ch){
       num[ch-'0']++;                 //将字符ASCII码对应的下标的值加一,表示其出现次数加一
       if(num[ch-'0']==1)
           chuxian.push_back(ch);//如果是第一次出现,存入chuxian

    }
    for(int i=0;i<chuxian.size();i++){
        if(num[chuxian[i]-'0']==1){                  //寻找第一个唯一出现一次的字符
            out.push_back(chuxian[i]);            //将这组数据的结果存入输出的容器中
            break;
        }
    }
  }
/***************数据处理结束,输出结果*********************/
    for(int i=0;i<out.size();i++){                //输出每组数据的结果
        cout<<out[i]<<endl;
    }
  //  system("PAUSE");
    return 0;
}
发表于 2015-08-12 09:43:43 回复(0)
我们可以定义哈希值(key)是字符,而值(value)是该字符出现的次数,同时我们还需要从头开始扫描字符串两次,第一次扫描字符串时,每扫描一个字符就在哈希表的对应项中把次数加1,接下来第二次扫描时,每扫描到一个字符就能从哈希表中得到该字符出现的次数,这样第一个只出现一次的字符就是符合要求的输出!
发表于 2015-08-14 07:50:10 回复(1)
请无视以下题面补完+出数据+写标程的人的胡言乱语:

为什么我的Markdown+MathJax题面上当天的环境去,居然把串长106变成了106?!?!
1000000和106完全2个难度啊!
不过没办法,只能顺应错误的题目造数据给做最终评测了。

这个题的方法很简单,每个字符反正对应一个ASCII码,计每个字符出现的下标即可。
需要2个特别的常量来表示2中情况:
1、这个字符没出现过(标程里为0)
2、这个字符多次出现(标程里为-1)
最后去检查一下这范围在[0x21,0x7F)间的字符,找有效的出现下标最小的字符,输出即可
复杂度O(|S|+94)

这个题倒是在数据被迫削弱后过了一大片,看到下面评论里好像有O(n*n*n)的写法,估计也只能被放过了(可恶啊,一定要卡死的,居然放过了)

以下是标程:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

typedef long long ll;

const int MAXN=1000000;

int idx[256];
int T;
char str[MAXN+5];

int main(){
	for(scanf("%d",&T);T--;){
		scanf("%s",str+1);
		memset(idx,0,sizeof(idx));
		for(int i=1;str[i];i++){
			if(idx[str[i]]==0){
				idx[str[i]]=i;
			}else{
				idx[str[i]]=-1;
			}
		}
		char ans='\0';
		for(int i=0x21;i<0x7F;i++){
			if(idx[i]>0){
				if(ans==0||idx[ans]>idx[i]) ans=i;
			}
		}
		printf("%c\n",ans);
	}
    return 0;
}

发表于 2015-08-12 19:08:08 回复(8)
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class Main {

	public static void main(String[] args) {
		int T = 0;
		 // InputStreamReader 是字节流通向字符流的桥梁;
		 // 为了达到最高效率,可要考虑在 BufferedReader 内包装 InputStreamReader。例如: 
 		 // BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
		BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
		try {
			T = Integer.parseInt(bufferedReader.readLine());
			for(int i=0; i<T; i++){
				String str = bufferedReader.readLine();
				System.out.println(firstAppearsOnlyonce(str));
			}
		} catch (NumberFormatException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		
	}

	/**
	 * 找字符串中第一个只出现一次的字符
	 */
	private static char firstAppearsOnlyonce(String str) {
		int[] hash = new int[256];					//记录每个字符对应的个数,共有256个ASCII码
		for(int i=0; i<256; i++){
			hash[i] = 0;
		}
		for(int i=0; i<str.length(); i++){
			hash[str.charAt(i)] ++;					//建立一个字符与个数反映射关系!
		}
		for(int i=0; i<str.length(); i++){			//再遍历一遍字符串,找第一个出现一次字符
			if(hash[str.charAt(i)] == 1){
				return str.charAt(i);
			}
		}
		return '\0';
	}
}


发表于 2016-05-19 19:09:21 回复(4)
#include<iostream>
#include<string>
#include<unordered_map>
using namespace std;
int main(){
    int i,n;
    cin >> n;
    while( n-- ){
        unordered_map<char,int> mm;
        string str;
        cin >> str;
        for(i=0;i<str.size();i++)
            mm[ str[i] ] ++ ;
        for(i=0;i<str.size();i++){
           if(mm[ str[i] ] == 1){
               cout << str[i] << endl;
               break;
           }
        }
    }
    return 0;
}
//
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int main(){
    int i,n;
    scanf("%d",&n);
    while( n-- ){
        char ans='\0';
        int mm[256]={0};
        char str[1000005];
        scanf("%s",str);
        for(i=0;str[i];i++){
            if(mm[ str[i] ] == 0)
                mm[ str[i] ] = i+1;//首次出现过,记录其下标。
            else
                mm[ str[i] ] = -1;//重复出现。则不用再记录。
        }
        for(i=0x21;i<0x7f;i++){
           if(mm[ i ] > 0 ){
               if(ans == 0 || mm[i]<mm[ans])
                   ans = i ;
           }
        }
        printf("%c\n",ans);
    }
    return 0;
}
//
#include<stdio.h>
#include<string.h>
int main(){
    int i,n;
    scanf("%d",&n);
    while( n-- ){
        int mm[130]={0};
        char str[1000005];
        scanf("%s",str);
        for(i=0;str[i];i++)
            mm[ str[i] ] ++ ;
        for(i=0;str[i];i++){
           if(mm[ str[i] ] == 1){
               printf("%c\n",str[i]);
               break;
           }
        }
    }
    return 0;
}

编辑于 2017-07-27 18:56:31 回复(1)
给出一个简单的解法,但在提交时显示运行超时/(ㄒoㄒ)/~~

发表于 2022-09-13 15:16:14 回复(1)
#include<iostream>
#include<string>
#include<map>
using namespace std;
char *once(int n,string arr[])
{
    char brr[n];//最终的字符存储在这里
    for(int i=0;i<n;i++)//从第一个字符串开始遍历
    {
        map<char,int>mp;
        for(int j=0;j<arr[i].length();j++)//每个字符串中各个元素的个数
        {
            mp[arr[i][j]]++;
        }
        for(int k=0;k<arr[i].length();k++)//从头开始遍历,遇到等于1的就直接保存当前值并且退出循环
        {
            if(mp[arr[i][k]]==1)
            {
                brr[i]=arr[i][k];
                break;//退出循环以防将之后只出现一次的元素算在内
            }
        }
    }
    return brr;
}
int main()
{
    int n;
    cin>>n;
    string arr[n];
    
     for(int i=0;i<n;i++)
     {
         string temp="";
         cin>>temp;
         arr[i]=temp;        
     }

   for(int i=0;i<n;i++)//输出的时候要输出的是每个元素,不能直接输出首地址
   {
    cout<<once(n,arr)[i]<<endl;

   }
    return 0;
}

发表于 2021-07-02 21:10:26 回复(0)