final class UnionFindTree2 {
    
    private enum Parent {
        case element(Int)
        case root(groupSize: Int)
    }
    
    private var parents: [Parent]
    
    init(size: Int) {
        self.parents = [Parent](repeating: .root(groupSize: 1), count: size)
    }
    
    func group(of element: Int) -> (representative: Int, size: Int) {
        let parentOfElement = parents[element]
        switch parentOfElement {
        case .element(let parent):
            let (representative, groupSize) = group(of: parent)
            self.parents[element] = .element(representative)
            return (representative: representative, size: groupSize)
        case .root(let groupSize):
            return (representative: element, size: groupSize)
        }
    }
    
    func sameGroupContains(_ a: Int, and b: Int) -> Bool {
        group(of: a) == group(of: b)
    }
    
    func uniteGroups(of a: Int, and b: Int) {
        var smallerGroup = group(of: a)
        var biggerGroup = group(of: b)
        guard smallerGroup.representative != biggerGroup.representative else { return }
        if smallerGroup.size > biggerGroup.size {
            swap(&smallerGroup, &biggerGroup)
        }
        self.parents[biggerGroup.representative] = .root(groupSize: smallerGroup.size + biggerGroup.size)
        self.parents[smallerGroup.representative] = .element(biggerGroup.representative)
    }
}

func main(input1: String = readLine()!) {
    let integers = input1.split(separator: " ").map { Int($0)! }
    let n = integers[0]
    let m = integers[1]
    
    let tree = UnionFindTree2(size: n)
    for _ in 0..<m {
        let integers = readLine()!.split(separator: " ").map { Int($0)! }
        let a = integers[0] - 1
        let b = integers[1] - 1
        tree.uniteGroups(of: a, and: b)
    }
    var maxGroupSize = 0
    for someone in 0..<n {
        let groupSize = tree.group(of: someone).size
        if maxGroupSize < groupSize {
            maxGroupSize = groupSize
        }
    }
    print(maxGroupSize)
}

main()