Bài tập về vòng lặp

Liên hệ QC

ndu96081631

Huyền thoại GPE
Thành viên BQT
Super Moderator
Tham gia
5/6/08
Bài viết
30,703
Được thích
53,930
Những ai đã từng xem qua bài viết này: Giới thiệu Cơ bản về vòng lặp For . . . next của sư phụ ptm0412 giờ hãy cùng làm 1 vài bài tập từ đơn giản đến nâng cao nhé
Xin mở màn bằng 1 bài tập sau:

Bài tập 01:

Hãy tính xem từ năm 1900 đến nay có bao nhiêu ngày thuộc dạng THỨ SÁU NGÀY 13
------------------------
Các bạn ai có bài tập gì hay xin post lên đây nhé! Cảm ơn
 
Chỉnh sửa lần cuối bởi điều hành viên:
Không biết như thế này có đúng không, Anh xem giúp nhé!
Mã:
Sub tinhngay()
Dim i As Date: Dim tong As Long
tong = 0
  For i = DateSerial(1900, 1, 1) To DateSerial(2010, 8, 17)
    If Weekday(i) = 6 And Day(i) = 13 Then tong = tong + 1
  Next
 MsgBox "So ngay la: " & tong
End Sub
 
Upvote 0
Cám ơn ndu đã nhắc tới và tiếp tục topic cũ. Quả thực lúc viết topic đó, mình nhớ gì viết nấy, và cũng muốn có nhiều bài tập hay hay từ thấp đến cao, nhưng nhất thời không nghĩ ra.

Nhân đây, mình rất mong mỏi những thành viên đang tập tành học VBA , nên tham gia topic này. Kể cả một vài thành viên đang viết code ầm ầm, nhưng theo nhận xét riêng thì đang rất mất căn bản trong tư duy logic.

Tư duy logic là cái cần thiết nhất, căn bản nhất mà người lập trình cần phải có. Các câu lệnh, cú pháp, hàm có sẵn, từ khoá, ... có thể mở Help lên xem, hoặc vào GPE hỏi, chứ tư duy logic thì không ai giúp được. Chỉ có thể rèn luyện bằng những bài tập nhỏ, những ứng dụng nhỏ, vận động trí óc tìm ra thuật toán để giải, ..

Rèn luyện tư duy, thì đây là 1 topic rất hay để các bạn tham gia và rèn luyện.

Đừng nghĩ rằng khi Excel đã có hàm giai thừa mà bắt các bạn tính giai thừa 1 số n bằng VBA là vô bổ, đó là rèn luyện suy luận đấy.


Hãy bắt đầu từ cái đơn giản nhất.


Gởi ndu:
Hãy từ từ nhé, hãy để vài người tham gia giải quyết cho rốt ráo 1 bài tập, rồi hãy đưa bài tập kế.
 
Upvote 0
Đúng, chắc vậy, nhưng bạn còn lãng fí kkhoảng 30 llần tthời gian cơ dđấy!

Thêm 1 vòng lặp nữa xem sao!
1 vòng lặp theo tháng, 1 vòng lặp theo năm . . . .
 
Upvote 0
Thêm 1 vòng lặp nữa xem sao!
1 vòng lặp theo tháng, 1 vòng lặp theo năm . . . .
Tôi nghĩ cũng chỉ cần 1 vòng lặp thôi.
PHP:
Sub Test()
Dim SoNgay As Long
    For i = 1 To (Year(Date) - 1900) * 12 + Month(Date) + (Day(Date) < 13)
        If Weekday(DateSerial(1900, i, 13)) = 6 Then SoNgay = SoNgay + 1
    Next
MsgBox SoNgay
End Sub
Trường hợp này dùng Do Until... Loop có lẽ là hay hơn
PHP:
Sub Test()
Dim SoNgay As Long, i As Long
Do Until DateSerial(1900, i, 13) > Date
    i = i + 1
    If Weekday(DateSerial(1900, i, 13)) = 6 Then SoNgay = SoNgay + 1
Loop
MsgBox SoNgay
End Sub
 
Upvote 0
Thêm 1 vòng lặp nữa xem sao!
1 vòng lặp theo tháng, 1 vòng lặp theo năm . . . .
Đúng là cần gì phải lặp theo ngày, vì ngày có sẵn là 13 rồi. Em sửa code lại như sau:
Mã:
Sub tinhngay1()
Dim i, j As Date: Dim tong As Long
tong = 0
 For j = 1900 To 2010
   For i = 1 To 12
    If Weekday(DateSerial(j, i, 13)) = 6 Then tong = tong + 1
   Next i
  Next j
 MsgBox "So ngay la: " & tong
End Sub
Tuy nhiên cái hàm Weekday(DateSerial(j, i, 13)) Em không biết thay hàm nào khác cả?
 
Upvote 0
MinhCong đã viết:
Mã:
Sub tinhngay1()
Dim i, j As Date: Dim tong As Long

- Vì thay thuật toán, nên i, j không phải là Date nữa, mà là Long
- Sự thực là i chưa khai báo kiểu, chỉ mới khai báo kiểu cho j và tong.
- Tính dư cho tháng 9 đến tháng 12 của năm 2010.
- Dùng Weekday đâu có vấn đề gì đâu?
 
Upvote 0
- Vì thay thuật toán, nên i, j không phải là Date nữa, mà là Long
- Sự thực là i chưa khai báo kiểu, chỉ mới khai báo kiểu cho j và tong.
Anh giải thích giúp Em sao biến i chưa được khai báo với, vì Em nghĩ đặt i và j cách nhau dấu "," thì nó hiểu hết chứ nhỉ?
Mã:
Sub tinhngay()
Dim i As Integer
Dim j As Long: Dim tong As Long
tong = 0
 For j = 1900 To 2010
   For i = 1 To 12
    If Weekday(DateSerial(j, i, 13)) = 6 And DateSerial(j, i, 13) <= Date Then tong = tong + 1
   Next i
  Next j
 MsgBox "So ngay la: " & tong
End Sub
 
Lần chỉnh sửa cuối:
Upvote 0
Anh Bill quy định thế mà, biết làm sao được.
Phải khai báo đầy đủ:

Dim i As Long, j As Long, tong As Long.

Thử như vầy sẽ biết: Dùng 1 dòng lệnh kiểm tra:

i = "GPE"

Nếu khai báo đủ như dòng trên, thì dòng lệnh này sẽ báo lỗi Type Mismatch. Điều này có lợi khi muốn loại giá trị không thích hợp.
Nếu khai báo thiếu, anh Bill thấy text cũng mặc kệ.
 
Lần chỉnh sửa cuối:
Upvote 0
Những ai đã từng xem qua bài viết này: Giới thiệu Cơ bản về vòng lặp For . . . next của sư phụ ptm0412 giờ hãy cùng làm 1 vài bài tập từ đơn giản đến nâng cao nhé
Xin mở màn bằng 1 bài tập sau:

Bài tập 01:

Hãy tính xem từ năm 1900 đến nay có bao nhiêu ngày thuộc dạng THỨ SÁU NGÀY 13
------------------------
Các bạn ai có bài tập gì hay xin post lên đây nhé! Cảm ơn
Theo tôi với vòng lặp thì bài này có thể finish được rồi, 1 vòng lặp hay 2 vòng lặp thì số lượng phép toán là như nhau, các bạn có thể tìm hiểu thêm phương pháp không dùng vòng lặp(đệ quy) xem sao.
Liên quan đến vòng lặp thì thường là các bài liên quan đến xử lý mảng, sắp xếp, ma trận, xử lý chuỗi ... Tôi xin góp vui 1 bài như sau
Bài tập 02:
Nhập vào 1 số N nguyên dương, in ra sheet hiện hành trên 1 vùng N cột, N dòng bắt đầu từ ô A1 với vùng đó chứa các số tự nhiên từ 1 đến N*N theo vòng xoáy ốc. Ví dụ N=5 ta sẽ phải in ra sheet hiện hành là
|A|B|C|D|E
1|1|2|3|4|5
2|16|17|18|19|6
3|15|24|25|20|7
4|14|23|22|21|8
5|13|12|11|10|9
 
Upvote 0
Theo tôi với vòng lặp thì bài này có thể finish được rồi, 1 vòng lặp hay 2 vòng lặp thì số lượng phép toán là như nhau, các bạn có thể tìm hiểu thêm phương pháp không dùng vòng lặp(đệ quy) xem sao.
Liên quan đến vòng lặp thì thường là các bài liên quan đến xử lý mảng, sắp xếp, ma trận, xử lý chuỗi ... Tôi xin góp vui 1 bài như sau
Bài tập 02:
Nhập vào 1 số N nguyên dương, in ra sheet hiện hành trên 1 vùng N cột, N dòng bắt đầu từ ô A1 với vùng đó chứa các số tự nhiên từ 1 đến N*N theo vòng xoáy ốc. Ví dụ N=5 ta sẽ phải in ra sheet hiện hành là
|A|B|C|D|E
1|1|2|3|4|5
2|16|17|18|19|6
3|15|24|25|20|7
4|14|23|22|21|8
5|13|12|11|10|9
Bạn ơi! Bài tập này rất hay nhưng tôi e rằng quá khó so với trình độ của những bạn mới vào nghề (cả tôi cũng chưa nghĩ ra hướng giải quyết nữa đây)
Vậy... cứ từ từ nha bạn!
Nếu sư phụ ptm0412 hoặc các bạn khác nghĩ ra được bài nào đó ở tầm trung trở xuống, xin vui lòng gữi lên đây nhé
(Bài của rollover79, ai nghĩ ra thì cứ đưa code lên, không nghĩ được cũng không sao ---> Chúng ta cùng tiếp tục để nâng cao tay nghề thôi)
 
Upvote 0
Bài tập 03:
Chuẩn hoá 1 chuỗi đầu vào theo nguyên tắc: Không tồn tại 2 ký tự liền kề giống nhau, các ký tự không liền kề vẫn có thể giống nhau. Ví dụ với chuỗi đầu vào là "AABBBBCCCCDDAAAAAA" thì chuỗi sau khi chuẩn hoá là "ABCDA"
 
Upvote 0
Xin đóng góp một câu trả lời với 2 vòng lặp theo cách tiếp cận vừa xử lý nén vừa duyệt qua chuỗi
PHP:
Private Function Normalize(Optional InputString As String = "") As String
    ' Normalize all
    'AABBBBCCCCDDAAAAAA
    Dim xStr As String, Tmp As String, i As Long
    ' Get first occurent
    If InputString = "" Then
        xStr = "AABBBBCCCCDDAAAAAA"
    Else
        xStr = InputString
    End If
    While i < Len(xStr)
        Tmp = Mid(xStr, i + 1, 1)
        While InStr(xStr, Tmp & Tmp) > 0
            xStr = Replace(xStr, Tmp & Tmp, Tmp)
        Wend
        i = i + 1
        Debug.Print xStr
    Wend
    Normalize = xStr
End Function
Cách tiếp theo có thể dùng đệ quy hoặc duyệt qua chuỗi. Nhìn chung bài này có nhiều cách giải quyết.
Cách giải trên đây vẫn chưa phải là tối ưu do vẫn có một số vòng lặp bị thửa (giả định như chuỗi không còn phần tử lặp thì nó vẫn cứ phải duyệt qua cả chuỗi).
 
Lần chỉnh sửa cuối:
Upvote 0
Bài tập 03:
Chuẩn hoá 1 chuỗi đầu vào theo nguyên tắc: Không tồn tại 2 ký tự liền kề giống nhau, các ký tự không liền kề vẫn có thể giống nhau. Ví dụ với chuỗi đầu vào là "AABBBBCCCCDDAAAAAA" thì chuỗi sau khi chuẩn hoá là "ABCDA"
Bạn cho hỏi: Có phân biệt HOA - thường không? Hay người dùng tự định nghĩa lấy?
 
Upvote 0
Bài tập 03:
Chuẩn hoá 1 chuỗi đầu vào theo nguyên tắc: Không tồn tại 2 ký tự liền kề giống nhau, các ký tự không liền kề vẫn có thể giống nhau. Ví dụ với chuỗi đầu vào là "AABBBBCCCCDDAAAAAA" thì chuỗi sau khi chuẩn hoá là "ABCDA"
Tôi cũng góp vui bằng cách sử dụng hàm Trim()
PHP:
Function ConverStr(Str As String) As String
    Dim C As String
    Str = Application.WorksheetFunction.Trim(vbBack & Str & vbBack)
    Str = Replace(Str, " ", vbBack)
    i = 2
    Do Until i = Len(Str)
        C = Mid(Str, i, 1)
        If C <> vbBack Then Str = Replace(Application.WorksheetFunction.Trim(Replace(Str, C, " ")), " ", C)
        i = i + 1
    Loop
    ConverStr = Replace(Mid(Str, 2, Len(Str) - 2), vbBack, " ")
End Function
Nếu không phân biệt chữ hoa, chữ thường thì thêm một dòng lệnh Convert cả chuỗi sang chữ hoa hoặc chữ thường.
 
Upvote 0
Nếu không phân biệt chữ hoa, chữ thường thì thêm một dòng lệnh Convert cả chuỗi sang chữ hoa hoặc chữ thường.
Không phân biệt chữ hoa chữ thường nhưng kết quả trả về vẫn có chữ hoa và chữ thường tùy thuộc vào ký tự đầu tiên bị trùng lặp mà ta xét, ví dụ "aAABbbCCCdDdAa" thì kết quả là "aBCdA". Với yêu cầu đó thì có lẽ không dùng phương pháp này được.
 
Upvote 0
Không phân biệt chữ hoa chữ thường nhưng kết quả trả về vẫn có chữ hoa và chữ thường tùy thuộc vào ký tự đầu tiên bị trùng lặp mà ta xét, ví dụ "aAABbbCCCdDdAa" thì kết quả là "aBCdA". Với yêu cầu đó thì có lẽ không dùng phương pháp này được.
Cứ For Next bình thường là được rồi
- Đặt 1 biến tạm
- Quét chuổi từ 1 đến Len(Chuổi)
- Nếu biến tạm <> ký tư thứ i thi
a> Lấy ký tự thứ i này ráp vào 1 chuổi tạm khác
b) Cho biến tạm = Ký tự thứ i
- Tiếp tục vòng lập
- Cuối cùng lấy kết quả chính là chuổi tạm khác
----------
Phân biệt HOA thường hay không, cùng lắm chỉ xét thêm UCase nữa là xong!
Các bạn làm trước theo hướng dễ: Có phân biệt HOA - thường rồi sau đó hẳn tính tiếp
 
Upvote 0
Bài giải bài tập 02

Bài tập 02:
Nhập vào 1 số N nguyên dương, in ra sheet hiện hành trên 1 vùng N cột, N dòng bắt đầu từ ô A1 với vùng đó chứa các số tự nhiên từ 1 đến N*N theo vòng xoáy ốc. Ví dụ N=5 ta sẽ phải in ra sheet hiện hành là
|A|B|C|D|E
1|1|2|3|4|5
2|16|17|18|19|6
3|15|24|25|20|7
4|14|23|22|21|8
5|13|12|11|10|9
Tôi có một phương án cho bài tập này. Mời mọi người tham khảo.
PHP:
Sub Test()
Application.ScreenUpdating = False
Dim Rng As Range, Way As Boolean, Number As Long
ActiveSheet.UsedRange.Clear
Number = InputBox("Please enter your number:")
[A1].Value = 1
Set Rng = [B1]
Way = True
For i = 2 To Number * Number
    Rng.Value = i
    If Way Then
        If Rng.Column = 1 Or Rng.Column = Number Then
            Way = False
            Set Rng = Rng.Offset(IIf(Rng.Column > (Number / 2 + 0.5), 1, -1))
        ElseIf Rng.Offset(, IIf(Rng.Row < (Number / 2 + 0.5), 1, -1)).Value <> "" Then
            Way = False
            Set Rng = Rng.Offset(IIf(Rng.Column > (Number / 2 + 0.5), 1, -1))
        Else
            Set Rng = Rng.Offset(, IIf(Rng.Row > (Number / 2 + 0.5), -1, 1))
        End If
    Else
        If Rng.Row = 1 Or Rng.Row = Number Then
            Way = True
            Set Rng = Rng.Offset(, IIf(Rng.Row > (Number / 2 + 0.5), -1, 1))
        ElseIf Rng.Offset(IIf(Rng.Column > (Number / 2 + 0.5), 1, -1)).Value <> "" Then
            Way = True
            Set Rng = Rng.Offset(, IIf(Rng.Row > (Number / 2 + 0.5), -1, 1))
        Else
            Set Rng = Rng.Offset(IIf(Rng.Column > (Number / 2 + 0.5), 1, -1))
        End If
    End If
Next
Application.ScreenUpdating = True
End Sub
 
Upvote 0
Web KT
Back
Top Bottom