質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.47%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Q&A

解決済

6回答

3165閲覧

C言語の配列の並び替えでTime Limit Exceededというエラーが出ます。

alizona

総合スコア126

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

0グッド

0クリップ

投稿2021/09/23 05:52

編集2021/09/23 09:57

numsという配列を並び替える問題で、LeetCode内でTime Limit Exceededというエラーが出ます。

LeetCodeの問題です。

nums配列は、このようになっています。[0,0,1,1,1,2,2,3,3,4]

このnumsを重複がないように並び替えて、余った要素には、''を代入します。
並び替えた後のnums配列は、[0,1,2,3,4,
,,,,]です。

そしてプログラムは、重複のない数字の数である5を返します。

Time Limit Exceededというエラーを解決するためにどのように修正すればいいでしょうか?

//修正前

C

1 2int removeDuplicates(int* nums, int numsSize){ 3 4 5 int i; 6 int j; 7 int num; 8 num=numsSize; 9 10 11 for (i = 0;i < numsSize;i++) { 12 if(i!=0){ 13 if(nums[i-1]==nums[i]){ 14 num--;//重複があった分をマイナスする。ユニークな数値の数にする 15 16 for(j=i; j<numsSize-1;j++){//重複が確認されたので、全ての要素を左に詰めるためのfor loop 17 nums[j]=nums[j+1]; 18 19 if(numsSize-1==j+1){ 20 nums[j+1]='_';//要素の最後には'_'を代入 21 } 22 } 23 //重複があった場合は、左に詰めるから詰めた分を再度重複がないか確認するために、-1する。 24 i--; 25 } 26 } 27 } 28 return num; 29}

//修正後

C

1 2int removeDuplicates(int* nums, int numsSize){ 3 4 int i; 5 int num=0; 6 7 //ここでえらーが出ます。このコードは input[1,1] や、input[1]に対応するためのコードです。 8 if(nums[0]==nums[numsSize-1]){ 9 num++; 10 } 11 12 for (i = 1;i < numsSize;i++) { 13 14 15 if(nums[i-1]!=nums[i]){ 16 17 18 if(i==numsSize-1){ 19 nums[num]=nums[i-1]; 20 num++; 21 22 nums[num]=nums[i]; 23 num++; 24 25 }else{ 26 nums[num]=nums[i-1]; 27 num++; 28 } 29 } 30 } 31 32 33 return num; 34} 35 36 37

error

1================================================================= 2==30==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x6020000001b0 at pc 0x55a3fe08f25d bp 0x7fff6f41e710 sp 0x7fff6f41e700 3READ of size 4 at 0x6020000001b0 thread T0 4 #2 0x7f29855c20b2 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x270b2) 50x6020000001b1 is located 0 bytes to the right of 1-byte region [0x6020000001b0,0x6020000001b1) 6allocated by thread T0 here: 7 #0 0x7f2986207bc8 in malloc (/lib/x86_64-linux-gnu/libasan.so.5+0x10dbc8) 8 #3 0x7f29855c20b2 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x270b2) 9Shadow bytes around the buggy address: 10 0x0c047fff7fe0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 11 0x0c047fff7ff0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 12 0x0c047fff8000: fa fa 00 04 fa fa fd fa fa fa fd fa fa fa fd fa 13 0x0c047fff8010: fa fa 00 fa fa fa fd fa fa fa fd fa fa fa fd fa 14 0x0c047fff8020: fa fa fd fa fa fa fd fa fa fa fd fa fa fa 00 00 15=>0x0c047fff8030: fa fa fd fa fa fa[01]fa fa fa fa fa fa fa fa fa 16 0x0c047fff8040: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 17 0x0c047fff8050: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 18 0x0c047fff8060: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 19 0x0c047fff8070: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 20 0x0c047fff8080: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 21Shadow byte legend (one shadow byte represents 8 application bytes): 22 Addressable: 00 23 Partially addressable: 01 02 03 04 05 06 07 24 Heap left redzone: fa 25 Freed heap region: fd 26 Stack left redzone: f1 27 Stack mid redzone: f2 28 Stack right redzone: f3 29 Stack after return: f5 30 Stack use after scope: f8 31 Global redzone: f9 32 Global init order: f6 33 Poisoned by user: f7 34 Container overflow: fc 35 Array cookie: ac 36 Intra object redzone: bb 37 ASan internal: fe 38 Left alloca redzone: ca 39 Right alloca redzone: cb 40 Shadow gap: cc 41==30==ABORTING

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

fana

2021/09/23 06:00

> Time Limit Exceededというエラーが出ます 何の話ですか? それは「エラー」なのですか? どこぞのサイトで時間制限がある問題に取り組んでいて「そのコードだと遅ぇよ」って言われただけの話ではないのでしょうか?
dodox86

2021/09/23 06:01

競技プログラミング系のことをやっていて、プログラム実行の制限時間越えのことを言われているのでしょうか。(<C言語であれば数秒以内に完了とか) その場合、提示のコードでのやり方に問題があって、入力データによってはその時間内に完了できないのだと思われます。その問題のあるサイトのURL等を明示しましょう。
dodox86

2021/09/23 06:04

この欄にではなく、質問に加筆、修正するかたちで示してください。他の方々も閲覧するものです。
dodox86

2021/09/23 06:06

で、そのエラーの解決方法自体が課題なのだと思います。課題条件を満たせるよう充分に速いロジックを組むという。
episteme

2021/09/23 06:48

ソコの問題には "余った要素には、'_'を代入"なんて書いてないぞ。
dodox86

2021/09/23 07:31

成り行きをみるに、ご自身ではデバッガーなどを使って実行させていないとみましたが、どうでしょう。
alizona

2021/09/23 07:33

It does not matter what you leave beyond the returned k (hence they are underscores).
Zuishin

2021/09/23 07:38 編集

いやだから、_ を入れず放置していいってことでしょ。そもそも配列は int サイズで _ は char サイズだし。
alizona

2021/09/23 07:38

放置したら、もともとの数値残りませんか?
Zuishin

2021/09/23 07:41 編集

It does not matter. > It does not matter what you leave beyond the returned k (訳) k 以降の要素に何を残しても構いません
dodox86

2021/09/23 07:41

課題文中には > It does not matter what you leave beyond the first k elements. としか書いていなく、Exampleの方で (hence they are underscores) が追加されているので、 「kを超えて放置された要素は問わない。だから例として'_'で埋めとくよ。(意訳)」程度の意味ではないでしょうか。必須条件ではない。
alizona

2021/09/23 07:42

it does not matter whether underscore or something elseって意味かと思ってました。
dodox86

2021/09/23 07:43

(かぶった上の劣化意訳)
dodox86

2021/09/23 07:46

必須ではないけど、反対に言えば入れても良い。入れたところで適切なロジックでプログラムを書けばパスするはずです。問題には「O(1)で」とあるので。
jimbe

2021/09/23 16:52

「並び替え」では無くて「詰める」だけなんですね。
guest

回答6

0

ベストアンサー

アルゴリズムは皆さまと同じ考えと思いますので、コードだけ。

c

1int removeDuplicates(int* nums, int numsSize){ 2 if(nums == NULL || numsSize <= 0) return 0; //param check 3 int c = 0; 4 for(int i=1; i<numsSize; i++) { 5 if(nums[c] != nums[i]) nums[++c] = nums[i]; 6 } 7 return c+1; 8}

投稿2021/09/23 17:34

jimbe

総合スコア12659

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

alizona

2021/09/23 23:44

ありがとうございました。やっとスッキリしましたw
guest

0

Time Limit Exceeded どころか、いつになったら終わるのか?無限ループしてるんじゃないか?と思ったので、デバッグコードを埋め込んで i, num の値と配列 nums[] の内容を表示してみました。

C

1void pArr(int a[], int asize) // 配列の内容を表示する 2{ 3 for (int i = 0; i < asize; i++) { 4 if (a[i] >= 0 && a[i] <= 9) 5 printf("%d ", a[i]); 6 else 7 printf("_ "); 8 } 9 printf("\n"); 10} 11 12int removeDuplicates(int* nums, int numsSize) 13{ 14 int num, i, j; 15 16 num = numsSize; 17 for (i = 0; i < numsSize; i++) { 18 printf("i = %d, num = %2d: ", i, num); // 追加 for DEBUG 19 pArr(nums, numsSize); // 追加 for DEBUG 20 21 if (i != 0) { 22 if (nums[i - 1] == nums[i]) { 23 num--; // 重複があった分をマイナスする。ユニークな… 24

実行結果です。

i = 0, num = 10: 0 0 1 1 1 2 2 3 3 4 i = 1, num = 10: 0 0 1 1 1 2 2 3 3 4 i = 1, num = 9: 0 1 1 1 2 2 3 3 4 _ i = 2, num = 9: 0 1 1 1 2 2 3 3 4 _ i = 2, num = 8: 0 1 1 2 2 3 3 4 _ _ i = 2, num = 7: 0 1 2 2 3 3 4 _ _ _ i = 3, num = 7: 0 1 2 2 3 3 4 _ _ _ i = 3, num = 6: 0 1 2 3 3 4 _ _ _ _ i = 4, num = 6: 0 1 2 3 3 4 _ _ _ _ i = 4, num = 5: 0 1 2 3 4 _ _ _ _ _ i = 5, num = 5: 0 1 2 3 4 _ _ _ _ _ i = 6, num = 5: 0 1 2 3 4 _ _ _ _ _ i = 6, num = 4: 0 1 2 3 4 _ _ _ _ _ i = 6, num = 3: 0 1 2 3 4 _ _ _ _ _ i = 6, num = 2: 0 1 2 3 4 _ _ _ _ _ i = 6, num = 1: 0 1 2 3 4 _ _ _ _ _ i = 6, num = 0: 0 1 2 3 4 _ _ _ _ _ i = 6, num = -1: 0 1 2 3 4 _ _ _ _ _ i = 6, num = -2: 0 1 2 3 4 _ _ _ _ _ i = 6, num = -3: 0 1 2 3 4 _ _ _ _ _ i = 6, num = -4: 0 1 2 3 4 _ _ _ _ _ i = 6, num = -5: 0 1 2 3 4 _ _ _ _ _ i = 6, num = -6: 0 1 2 3 4 _ _ _ _ _ i = 6, num = -7: 0 1 2 3 4 _ _ _ _ _ i = 6, num = -8: 0 1 2 3 4 _ _ _ _ _ i = 6, num = -9: 0 1 2 3 4 _ _ _ _ _ (以下、延々と続きます)

これ、nums[5] ~ nums[9] に '_' が書き込まれた後も
if (nums[i - 1] == nums[i]) 条件は成立し続けるので無限ループしてるようですね。
デバッガ使うのが筋でしょうが、こんな風に簡単なデバッグコードを埋め込む(いわゆるprintfデバッグ)だけでも調査はできますよ。

投稿2021/09/23 07:00

rubato6809

総合スコア1380

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

alizona

2021/09/23 08:33

ありがとうございました。
guest

0

"左に詰める"に時間食ってるんでしょうか。
だったらそんな処理やんなきゃいい。

C

1#include <stdio.h> 2 3// 空いた位置に'_'を埋めてはいない(その必要はないから) 4 5int removeDuplicates(int* nums, int numsSize) { 6 7 int read_inx; // 読む位置 8 int write_inx = 0; // 書く位置 9 int last_value ; // 最後に書いた値 10 11 for ( read_inx = 0; read_inx < numsSize; ++read_inx ) { 12 // 最初の一回、もしくは"最後に書いた値"と"今読んでる値"が異なるなら 13 // "今読んでる値" を 書く("最後に書いた値"も更新) 14 if ( read_inx ==0 || last_value != nums[read_inx] ) { 15 nums[write_inx++] = last_value = nums[read_inx]; 16 } 17 } 18 return write_inx; // 重複を取り除いた後の要素数 19} 20 21int main() { 22 int nums[10] = { 0,0,1,1,1,2,2,3,3,4 }; 23 int numsSize = 10; 24 25 numsSize = removeDuplicates(nums, numsSize); 26 27 for ( int i = 0; i < numsSize; ++i ) { 28 printf("%d ", nums[i]); 29 } 30 return 0; 31}

投稿2021/09/23 06:39

episteme

総合スコア16614

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

alizona

2021/09/23 09:54 編集

ありがとうございます。アドバイスいただいたコードを理解できました。また正常に動作しました。 今、lastValueを使わない方法も探してます。
episteme

2021/09/23 10:17

なくてもできる(できた)。なんてことないっしょ。
alizona

2021/09/23 10:21

わかりました。ありがとうございました。
guest

0

ここまで書けているので、ある程度ご理解されている前提でお話します。

・要求されている答えが要素数 num だけなのであれば、
num = 1 としておいて、配列を前から順に読んでいき、
「値が変化するところ」 0->1 とか 1->2 とかで num をインクリメントするだけでよいと思います。

次に、

・配列 nums も要素数 num も両方求められている場合、
重複のたびに配列を詰めていたのでは、時間がかかってしまうので、
読み込み用のインデクス src_i = 1 、書き込み用のインデクス dst_i = 0
として、読み込み用インデクス src_i で forを回して 配列を前から順に読んでいき、
「前の値」(nums[src_i-1])と「今の値」(nums[src_i])を比較します。 
もし値が変化していたら、「前の値」を nums[dst_i] に格納し、dst_i をインクリメントします。
dst_i が src_i に追いつく(dst_i >= src_i)ことはない、
ということを利用します。
要は、詰める、のではなく、配列を読みながら、同じ配列内に値が重複しないように
答えの配列を作っていくイメージです。

さっぱり、わからなかったらご質問ください。

投稿2021/09/23 06:26

ak.n

総合スコア291

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

alizona

2021/09/23 06:36

ありがとうございます。アドバイスいただいた通りにコードが書けているでしょうか? Runtime Errorが原因はわかっていません。エラーと、コードを質問分に追記しました。
ak.n

2021/09/23 06:50

いえ、色々間違っています。 まず、 最初の num = 0 です。最初の値の格納先になります。 次に、for (i=0 ですが i=1 からスタートすれば if (i!=0)は不要ですね、for のなかで、何度もチェックするような処理はできるだけ減らした方がいいです。 それから、nums[num]=nums[i]; は nums[num]=nums[i-1]; ですね。 あとは、最後に配列の末尾まで、'_' で埋める処理は、お任せします。
ak.n

2021/09/23 06:59

ん-んとですね、まず、何を自分がやろうとしているかを、よく理解して頂きたいと思います。 配列のインデクスは0から始まりますね、0番から10番までのマスの絵を書いて、そこに数字を並べてみて、 どういう処理をしようとしているか、よーーく考えてから、書いてくださいね。
alizona

2021/09/23 07:40

"それから、nums[num]=nums[i]; は nums[num]=nums[i-1];" ということが理解できなかったのですが、自分のコードを実行したところoutputの値は正解です。 ただ、Runtime Errorなのですが、それとは関係はないですよね?
alizona

2021/09/23 09:52

質問欄の修正後コードの中の if(nums[0]==nums[numsSize-1]){ num++; }でエラーが出るのですがアドバイスいただけないですか?
alizona

2021/09/23 09:55

input [1,1] の時にoutput [ ]にならないようにするためのコードです。 また、input[1]の時に、[ ] にならないようにするためです。
jimbe

2021/09/23 17:31 編集

横から失礼します。 numsSize が 0 (input が [] ) の場合に nums[numsSize-1] は領域外を指してしまいますよ。
guest

0

とりあえず,「そのコードだと遅ぇよ」って話であれば,

//重複が確認されたので、全ての要素を左に詰める

という処理が最も重いであろう(というか,それくらいしか処理が無い)から,
この処理を実施する回数をなるべく減らすことを考えてみては.

例えば,

1,1,1,1,2,3,....

っていう具合に1が重複しているとして,
「左に1個分詰める」処理を3回も実施せずとも「左に3個分詰める」処理を1回やればいいよね,的な話は誰でも思いつくでしょう.
まずはそのくらいのことをやってみてはどうでしょうか.

投稿2021/09/23 06:09

fana

総合スコア11660

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

alizona

2021/09/23 06:12

やってみます。ありがとうございます。
fana

2021/09/23 06:20 編集

それでも「遅い」と言われるなら(←多分,言われるものと予想),そもそも「いちいち詰めない」ことを考えればよいかと.
alizona

2021/09/23 07:53

nums[i-1]とnums[i]を比較して、値が違うときだけ代入する方法にしました。
guest

0

google翻訳
制限時間を超えました

これはC言語上でのエラーではなく、実行環境でのエラーじゃないでしょうか
ってことですんで、どういう環境で実行させてるんでしょうか。
なにかの課題ってことでしょうか

投稿2021/09/23 05:57

編集2021/09/23 06:01
y_waiwai

総合スコア87782

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

alizona

2021/09/23 06:00

返信ありがとうございます。leetcodeです。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.47%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問