0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

paizaラーニングレベルアップ問題集の【文字列処理メニュー】をCでやってみた。

Posted at

paizaラーニングレベルアップ問題集の【文字列処理メニュー】をC言語でやってみました。但し、最初の18問は、各問題最低1個は<string.h>を封印したコードを掲載しています。


BASIC

文字列の出力
#include <stdio.h>

int main() {
	puts("paiza");
	return 0;
}

他の言語はコチラ


文字列の受け取り

Perlっぽく。

#include <stdio.h>

char* chomp(char *s) {
	char *p = s;
	while (*p) p++;
	while (p-- > s) if (*p == '\n') *p = '\0'; else break;
	return s;
}

int main() {
	char s[102];
	puts(chomp(fgets(s, sizeof(s), stdin)));
	return 0;
}

他の言語はコチラ


i文字目の出力

$S$の文字数の条件がありませんが、仮に100としています。

#include <stdio.h>

int main() {
	char s[101];
	scanf("%s", s);
	int i;
	scanf("%d", &i);
	putchar(s[i-1]);
	return 0;
}

文字列の条件判定
<string.h>不使用
#include <stdio.h>

const char *str = "paiza";

int main() {
	char s[101];
	scanf("%s", s);
	int i = 0;
	while (s[i] && str[i]) {
		if (s[i] != str[i]) break;
		i++;
	}
	puts(s[i] == str[i] ? "YES" : "NO");
	return 0;
}

<string.h>使用
#include <stdio.h>
#include <string.h>

int main() {
	char s[101];
	scanf("%s", s);
	puts(strcmp(s, "paiza") == 0 ? "YES" : "NO");
	return 0;
}

他の言語はコチラ


文字列の文字数
<string.h>不使用
#include <stdio.h>

int main() {
	char s[10001];
	scanf("%s", s);
	int len = 0;
	for (char *c = s; *c; c++) {
		len++;
	}
	printf("%d\n", len);
	return 0;
}

<string.h>使用
#include <stdio.h>
#include <string.h>

int main() {
	char s[10001];
	scanf("%s", s);
	printf("%d\n", (int) strlen(s));
	return 0;
}

他の言語でもlen関数やlengthメソッド等があります。


文字の検索
<string.h>不使用
#include <stdio.h>

int main() {
	char s[10001];
	scanf("%s\n", s); // \nを入れないと次で改行コードを拾ってしまう
	char c;
	scanf("%c", &c);
	for (int i = 0; s[i]; i++) {
		if (s[i] == c) {
			printf("%d\n", i + 1);
			break;
		}
	}
	return 0;
}

<string.h>使用
#include <stdio.h>
#include <string.h>

int main() {
	char s[10002];
	fgets(s, sizeof(s), stdin);
	char c = (char) getchar();
	printf("%d\n", (int) (strchr(s, c) - s) + 1);
	return 0;
}

文字列の連結
<string.h>不使用
#include <stdio.h>

int main() {
	int n;
	scanf("%d", &n);
	char t[1000001] = "";
	char *p = t;
	for (int i = 0; i < n; i++) {
		char s[10001];
		scanf("%s", s);
		char *c = s;
		while (*c) *p++ = *c++;
	}
	puts(t);
	return 0;
}

<string.h>不使用2

sprintf関数の返却値と、アドレス演算を利用して、
他の言語と同様に+=を使って連結してみました。

#include <stdio.h>

int main() {
	int n;
	scanf("%d", &n);
	char t[1000001] = "";
	char *p = t;
	for (int i = 0; i < n; i++) {
		char s[10001];
		scanf("%s", s);
		p += sprintf(p, "%s", s);
	}
	puts(t);
	return 0;
}

<string.h>使用
#include <stdio.h>
#include <string.h>

int main() {
	int n;
	scanf("%d", &n);
	char t[1000001] = "";
	for (int i = 0; i < n; i++) {
		char s[10001];
		scanf("%s", s);
		strcat(t, s);
	}
	puts(t);
	return 0;
}

他の言語では、Stringクラスの文字列を+=演算子で結合するよりも、stringstreamStringBufferクラスを用いた方がベターでしょう。


NORMAL

部分文字列
<string.h>不使用1

1文字ずつ出力します。

#include <stdio.h>

int main() {
	char s[10001];
	scanf("%s", s);
	int i, j;
	scanf("%d %d", &i, &j);
	i--;
	for (; i < j; i++) putchar(s[i]);
	puts("");
	return 0;
}

<string.h>不使用2

ポインタを用います。

#include <stdio.h>

int main() {
	char s[10001];
	scanf("%s", s);
	int i, j;
	scanf("%d %d", &i, &j);
	i--;
	char t[j-i+1];
	char *p = t;
	for (; i < j; i++) *p++ = s[i];
	*p = '\0';
	puts(t);
	return 0;
}

<string.h>使用
#include <stdio.h>
#include <string.h>

int main() {
	char s[10001];
	scanf("%s", s);
	int i, j;
	scanf("%d %d", &i, &j);
	i--;
	char t[j-i+1];
	strncpy(t, s+i, j-i);
	t[j-i] = '\0';
	puts(t);
	return 0;
}

他の言語はコチラが参考になると思います。


文字列の挿入
<string.h>不使用1
#include <stdio.h>

int main() {
	char s[10001];
	scanf("%s", s);
	char t[10001];
	scanf("%s", t);
	int n;
	scanf("%d", &n);
	for (int i = 0; i < n; i++) putchar(s[i]);
	printf("%s", t);
	for (char* c = s + n; *c; c++) putchar(*c);
	return 0;
}
<string.h>不使用2
#include <stdio.h>

int main() {
	char s[10001];
	scanf("%s", s);
	char t[10001];
	scanf("%s", t);
	int n;
	scanf("%d", &n);
	char u[20001] = "";
	char *p = u;
	for (int i = 0; i < n; i++) *p++ = s[i];
	char *c = t;
	while (*c) *p++ = *c++;
	c = s + n;
	while (*c) *p++ = *c++;
	*p = '\0';
	puts(u);
	return 0;
}
<string.h>使用
#include <stdio.h>
#include <string.h>

int main() {
	char s[10001];
	scanf("%s", s);
	char t[10001];
	scanf("%s", t);
	int n;
	scanf("%d", &n);
	char u[20001] = "";
	strncpy(u, s, n);
	strcat(u, t);
	strcat(u, s + n);
	puts(u);
	return 0;
}

文字列の書き換え
#include <stdio.h>

int main() {
	char s[101];
	scanf("%s", s);
	int i;
	char c;
	scanf("%d %c", &i, &c);
	s[i-1] = c;
	puts(s);
	return 0;
}

  • Javaでは受け取った文字列をtoCharArrayする必要があります
import java.util.*;

public class Main {
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		char[] s = sc.next().toCharArray();
		int i = sc.nextInt() - 1;
		char c = sc.next().charAt(0);
		s[i] = c;
		System.out.println(new String(s));
		sc.close();
	}
}

  • Pythonでは受け取った文字列をlistに変換する必要があります
s = list(input())
i, c = input().split()
i = int(i) - 1
s[i] = c
print(''.join(s))

文字列から数値への変換
<stdlib.h>不使用
#include <stdio.h>

int main() {
	char s[9];
	scanf("%s", s);
	int n = 0;
	for (char *c = s; *c; c++) n = 10 * n + (*c - '0');
	printf("%d\n", n - 813);
	return 0;
}
<stdlib.h>使用
#include <stdio.h>
#include <stdlib.h>

int main() {
	char s[9];
	scanf("%s", s);
	int n = atoi(s);
	printf("%d\n", n - 813);
	return 0;
}

数値から文字列への変換
#include <stdio.h>

int main() {
	long long x;
	scanf("%lld", &x);
	long long y;
	scanf("%lld", &y);
	int n;
	scanf("%d", &n);
	char s[13];
	sprintf(s, "%lld", x + y);
	putchar(s[n-1]);
	puts("");
	return 0;
}

大文字から小文字への変換
<ctype.h>不使用
#include <stdio.h>

int main() {
	char s[10001];
	scanf("%s", s);
	for (char *c = s; *c; c++)
		if ('A' <= *c && *c <= 'Z')
			*c = *c - 'A' + 'a';
	puts(s);
	return 0;
}
<ctype.h>使用
#include <stdio.h>
#include <ctype.h>

int main() {
	char s[10001];
	scanf("%s", s);
	for (char *c = s; *c; c++)
		if (isupper(*c))
			*c = tolower(*c);
	puts(s);
	return 0;
}

小文字から大文字への変換
<ctype.h>不使用
#include <stdio.h>

int main() {
	char s[10001];
	scanf("%s", s);
	for (char *c = s; *c; c++)
		if ('a' <= *c && *c <= 'z')
			*c = *c - 'a' + 'A';
	puts(s);
	return 0;
}
<ctype.h>使用
#include <stdio.h>
#include <ctype.h>

int main() {
	char s[10001];
	scanf("%s", s);
	for (char *c = s; *c; c++)
		if (islower(*c))
			*c = toupper(*c);
	puts(s);
	return 0;
}

大文字小文字の反転
<ctype.h>不使用
#include <stdio.h>

int main() {
	char s[101];
	scanf("%s", s);
	for (char *c = s; *c; c++)
		if ('A' <= *c && *c <= 'Z')
			*c = *c - 'A' + 'a';
		else if ('a' <= *c && *c <= 'z')
			*c = *c - 'a' + 'A';
	puts(s);
	return 0;
}
<ctype.h>使用
#include <stdio.h>
#include <ctype.h>

int main() {
	char s[10001];
	scanf("%s", s);
	for (char *c = s; *c; c++)
		if (isupper(*c))
			*c = tolower(*c);
		else if (islower(*c))
			*c = toupper(*c);
	puts(s);
	return 0;
}

文字列の検索
<string.h>不使用
#include <stdio.h>

char* find(const char *s, const char *t) {
	for (const char *p = s;; p++) {
		if (*p) {
			for (int i = 0;; i++) {
				if (t[i]) {
					if (!p[i]) return NULL;
					if (p[i] != t[i]) break;
				} else {
					return (char*) p;
				}
			}
		} else {
			return NULL;
		}
	}
}

int main() {
	char s[101];
	scanf("%s", s);
	char t[101];
	scanf("%s", t);
	puts(find(s, t) ? "YES" : "NO");
	return 0;
}
<string.h>使用
#include <stdio.h>
#include <string.h>

int main() {
	char s[101];
	scanf("%s", s);
	char t[101];
	scanf("%s", t);
	puts(strstr(s, t) ? "YES" : "NO");
	return 0;
}

文字列の反転
#include <stdio.h>

int main() {
	char s[1001];
	scanf("%s", s);
	char *p = s;
	while (*p) p++;
	char t[1001] = "";
	char *q = t;
	while (p > s) *q++ = *(--p);
	puts(t);
	return 0;
}

回文判定
#include <stdio.h>

int is_palindrome(const char* s) {
	const char *p = s;
	while (*p) p++;
	const char *q = s;
	while(q < --p) if (*q++ != *p) return 0;
	return 1;
}

int main() {
	char s[1001];
	scanf("%s", s);
	puts(is_palindrome(s) ? "YES" : "NO");
	return 0;
}

前問の反転文字列を用いて比較する方法もあります。


ADVANCE

文字列の分割

分割した文字列を文字列の配列に格納することは省略します。

<string.h>不使用1
#include <stdio.h>

int main() {
	char s[101];
	scanf("%s", s);
	char t[101];
	char *q = t;
	for (char *p = s; *p; p++) {
		if (*p == ',') {
			*q = '\0';
			puts(t);
			q = t;
		} else {
			*q++ = *p;
		}
	}
	*q = '\0';
	puts(t);
	return 0;
}
<string.h>不使用2
#include <stdio.h>

int main() {
	char s[101];
	scanf("%s", s);
	for (char *p = s; *p; p++) {
		if (*p == ',') {
			*p = '\n';
		}
	}
	puts(s);
	return 0;
}
<string.h>使用
#include <stdio.h>
#include <string.h>

int main() {
	char s[101];
	scanf("%s", s);
	char* t = strtok(s, ",");
	while (t) {
		puts(t);
		t = strtok(NULL, ",");
	}
	return 0;
}

日時データの変換その1
解答例1
#include <stdio.h>

int main() {
	int year, month, day, hour, minute;
	scanf("%d/%d/%d/%d:%d", &year, &month, &day, &hour, &minute);
	printf("%04d\n", year);
	printf("%02d\n", month);
	printf("%02d\n", day);
	printf("%02d\n", hour);
	printf("%02d\n", minute);
	return 0;
}
解答例2
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main() {
	char datetime[17];
	scanf("%s", datetime);
	printf("%04d\n", atoi(strtok(datetime, "/")));
	printf("%02d\n", atoi(strtok(NULL, "/")));
	printf("%02d\n", atoi(strtok(NULL, "/")));
	printf("%02d\n", atoi(strtok(NULL, ":")));
	printf("%02d\n", atoi(strtok(NULL, "")));
	return 0;
}

日時データの変換その2
解答例1
#include <stdio.h>

int main() {
	int year, month, day, hour, minute;
	scanf("%d/%d/%d %d:%d", &year, &month, &day, &hour, &minute);
	printf("%04d\n", year);
	printf("%02d\n", month);
	printf("%02d\n", day);
	printf("%02d\n", hour);
	printf("%02d\n", minute);
	return 0;
}
解答例2
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main() {
	char date[11], time[6];
	scanf("%s %s", date, time);
	printf("%04d\n", atoi(strtok(date, "/")));
	printf("%02d\n", atoi(strtok(NULL, "/")));
	printf("%02d\n", atoi(strtok(NULL, "/")));
	printf("%02d\n", atoi(strtok(time, ":")));
	printf("%02d\n", atoi(strtok(NULL, ":")));
	return 0;
}

数値判定
<ctype.h>不使用
#include <stdio.h>

int is_numeric(const char* s) {
	for (const char *c = s; *c; c++) {
		if (*c < '0' || '9' < *c) return 0;
	}
	return 1;
}

int main() {
	char s[10001];
	scanf("%s", s);
	puts(is_numeric(s) ? "YES" : "NO");
	return 0;
}
<ctype.h>使用
#include <stdio.h>
#include <ctype.h>
#include <stdbool.h>

bool is_numeric(const char* s) {
	for (const char *c = s; *c; c++) {
		if (!isdigit(*c)) return false;
	}
	return true;
}

int main() {
	char s[10001];
	scanf("%s", s);
	puts(is_numeric(s) ? "YES" : "NO");
	return 0;
}

重複の削除
解答例1(O(|S|^2)解法)
#include <stdio.h>

int main() {
	char s[1001];
	scanf("%s", s);
	for (int i = 0; s[i]; i++) {
		for (int j = 0; j <= i; j++) {
			if (j == i) putchar(s[i]);
			else if (s[j] == s[i]) break;
		}
	}
	puts("");
	return 0;
}
解答例2(O(|S|)解法)
#include <stdio.h>

int main() {
	char s[1001];
	scanf("%s", s);
	int count[10] = {};
	for (char *c = s; *c; c++) {
		int i = (int) (*c - '0');
		if (!count[i]++) putchar(*c);
	}
	puts("");
	return 0;
}

パスワード作成
解答例1
#include <stdio.h>

int main() {
	int N;
	scanf("%d", &N);
	char s[N + 1];
	for (int i = 0; i <= N; i++) s[i] = '\0';
	int Q;
	scanf("%d", &Q);
	for (int q = 0; q < Q; q++) {
		int k;
		char c;
		scanf("%d %c\n", &k, &c);
		s[k - 1] = c;
	}
	char C = (char) getchar();
	for (int i = 0; i < N; i++) if (!s[i]) s[i] = C;
	puts(s);
	return 0;
}
解答例2
#include <stdio.h>
#include <string.h>

int main() {
	int N;
	scanf("%d", &N);
	int Q;
	scanf("%d", &Q);
	int A[Q];
	char C[Q];
	for (int q = 0; q < Q; q++)
		scanf("%d %c\n", &A[q], &C[q]);
	char s[N + 1];
	memset(s, getchar(), sizeof(s));
	s[N] = '\0';
	for (int q = 0; q < Q; q++)
		s[A[q] - 1] = C[q];
	puts(s);
	return 0;
}

表記の訂正
方針
  1. 正しい小数点の位置を取得する。無い場合は末尾とする
  2. (ミス1対応)先頭の0を除去する。但し、小数点の直前の0は残す
  3. (ミス3対応)正しくない小数点を除去する
  4. (ミス2対応)末尾の不要な0を除去する
  5. 末尾が小数点になった場合、除去する
    • 今回は「答えが.0の形式になるような値は与えられません」ので不要ですが、一応実装します

解答例1
#include <stdio.h>

int main() {
	char S[10001];
	scanf("%s", S);
	int n = 0;
	int p = -1;
	while (S[n]) {
		if (S[n] == '.' && p == -1) p = n;
		n++;
	}
	if (p == -1) p = n;

	// miss 1
	int a = 0;
	while (S[a] == '0' && a < p - 1) {
		a++;
	}

	// miss 3
	char T[10001] = "";
	int m = 0;
	int q = -1;
	for (int i = a; i < n; i++) {
		if (S[i] == '.') {
			if (i == p) q = m;
			else continue;
		}
		T[m++] = S[i];
	}
	if (q == -1) q = m;

	// miss 2
	while (m > q && T[m-1] == '0') {
		T[--m] = '\0';
	}
	if (T[m-1] == '.') T[--m] = '\0';

	puts(T);
	return 0;
}

解答例2
#include <stdio.h>
#include <string.h>

int main() {
	char S[10001];
	scanf("%s", S);
	char *p = strchr(S, '.');

	// miss 1
	char *s = S;
	while ((int) (p - s) > 1 && *s == '0') s++;
	
	char T[10001] = "";
	strcpy(T, strtok(s, "."));
	if (p) {
		char *q = T + strlen(T);
		*q = '.';

		// miss 3
		char *t = strtok(NULL, ".");
		while (t) {
			strcat(T, t);
			t = strtok(NULL, ".");
		}

		// miss 2
		char *z = T + strlen(T);
		while (z > q && *(z-1) == '0') *(--z) = '\0';
		if (*(z-1) == '.') *(--z) = '\0';
	}
	
	puts(T);
	return 0;
}

数式の計算(1桁)
#include <stdio.h>
#include <string.h>
#include <ctype.h>

int main() {
	char s[10001];
	scanf("%s", s);
	int ans = 0;
	int tmp = 0;
	char op = '+';
	for (char *c = s; *c; c++) {
		if (strchr("+-", *c)) {
			if (op == '+') ans += tmp;
			else if (op == '-') ans -= tmp;
			op = *c;
		} else if (isdigit(*c)) {
			tmp = (int) (*c - '0');
		}
	}
	if (op == '+') ans += tmp;
	else if (op == '-') ans -= tmp;
	printf("%d\n", ans);
	return 0;
}

数式の計算
#include <stdio.h>
#include <string.h>
#include <ctype.h>

int main() {
	char s[10001];
	scanf("%s", s);
	int ans = 0;
	int tmp = 0;
	char op = '+';
	for (char *c = s; *c; c++) {
		if (strchr("+-", *c)) {
			if (op == '+') ans += tmp;
			else if (op == '-') ans -= tmp;
			tmp = 0;
			op = *c;
		} else if (isdigit(*c)) {
			int d = (int) (*c - '0');
			tmp = 10 * tmp + d;
		}
	}
	if (op == '+') ans += tmp;
	else if (op == '-') ans -= tmp;
	printf("%d\n", ans);
	return 0;
}

巨大な数の足し算(繰り上がりなし)

今回は

  • 全ての桁において繰り上がりが発生しない
  • オペランドの桁数が等しい

ので、上位桁から計算します。

#include <stdio.h>

int main() {
	char s[1001];
	scanf("%s", s);
	char t[1001];
	scanf("%s", t);
	char u[1001] = "";
	for (int i = 0; s[i]; i++) {
		// u[i] = (s[i] - '0') + (t[i] - '0') + '0';
		u[i] = s[i] + t[i] - '0'; // s[i]+t[i]でオーバーフローは発生しない
	}
	printf("%s\n", u);
	return 0;
}

巨大な数の足し算
#include <stdio.h>
#include <string.h>

int main() {
	char s[1001];
	scanf("%s", s);
	char t[1001];
	scanf("%s", t);
	char u[1002] = "";
	int n = (int) strlen(s);
	int c = 0; // carrying(繰り上がり)
	for (int i = n; i > 0; i--) {
		int d = c + (s[i-1] - '0') + (t[i-1] - '0');
		u[i] = d % 10 + '0';
		c = d / 10;
	}
	u[0] = c + '0';
	char *p = u;
	while (*p && *p == '0') p++;
	puts(p);
	return 0;
}
別解(オペランドの桁数が異なっても対応できるように)
#include <stdio.h>
#include <string.h>

int max(int a, int b) {
	return a > b ? a : b;
}

int main() {
	char s[1001];
	scanf("%s", s);
	int n = (int) strlen(s);
	char t[1001];
	scanf("%s", t);
	int m = (int) strlen(t);
	int k = max(n, m);
	char u[1002] = "";
	int c = 0; // carrying(繰り上がり)
	for (int i = 0; i < k; i++) {
		int d = c;
		if (i < n) d += (s[n - i - 1] - '0');
		if (i < m) d += (t[m - i - 1] - '0');
		u[k - i] = d % 10 + '0';
		c = d / 10;
	}
	u[0] = c + '0';
	char *p = u;
	while (*p && *p == '0') p++;
	puts(p);
	return 0;
}

巨大な数のかけ算
#include <stdio.h>
#include <string.h>

int main() {
	char s[1001];
	scanf("%s", s);
	int n = (int) strlen(s);
	int t;
	scanf("%d", &t);
	char u[1002] = "";
	int c = 0; // carrying(繰り上がり)
	for (int i = n; i > 0; i--) {
		int d = c + (s[i-1] - '0') * t;
		u[i] = d % 10 + '0';
		c = d / 10;
	}
	u[0] = c + '0';
	char *p = u;
	while (*p && *p == '0') p++;
	puts(p);
	return 0;
}
別解(乗数が2桁以上でも対応できるように)
#include <stdio.h>
#include <string.h>

int main() {
	char s[1001];
	scanf("%s", s);
	int n = (int) strlen(s);
	char t[1001];
	scanf("%s", t);
	int m = (int) strlen(t);
	char u[2001] = "";
	memset(u, '0', n + m);
	for (int j = m; j > 0; j--) {
		int c = 0; // carrying(繰り上がり)
		for (int i = n; i > 0; i--) {
			int d = (u[i+j-1] - '0') + c + (s[i-1] - '0') * (t[j-1] - '0');
			u[i+j-1] = d % 10 + '0';
			c = d / 10;
		}
		int k = 1;
		while (c) {
			int d = (u[j-k] - '0') + c;
			u[j-k] = d % 10 + '0';
			c = d / 10;
			k++;
		}
	}
	char *p = u;
	while (*p && *p == '0') p++;
	puts(p);
	return 0;
}

最後の2問は、言語によっては、入力値をreverseして計算した結果をreverseするのがいいかも。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?