Problem

You are given a string text. We want to display text on a screen of width w and height h. You can choose any font size from array fonts, which contains the available font sizes in ascending order.

You can use the FontInfo interface to get the width and height of any character at any available font size.

The FontInfo interface is defined as such:

1
2
3
4
5
6
7
8
9
interface FontInfo {
  // Returns the width of character ch on the screen using font size fontSize.
  // O(1) per call
  public int getWidth(int fontSize, char ch);

  // Returns the height of any character on the screen using font size fontSize.
  // O(1) per call
  public int getHeight(int fontSize);
}

The calculated width of text for some fontSize is the sum of every getWidth(fontSize, text[i]) call for each 0 <= i < text.length (0-indexed). The calculated height of text for some fontSize is getHeight(fontSize). Note that text is displayed on a single line.

It is guaranteed that FontInfo will return the same value if you call getHeight or getWidth with the same parameters.

It is also guaranteed that for any font size fontSize and any character ch:

  • getHeight(fontSize) <= getHeight(fontSize+1)
  • getWidth(fontSize, ch) <= getWidth(fontSize+1, ch)

Return the maximum font size you can use to displaytext on the screen. If text cannot fit on the display with any font size, return -1.

Examples

Example 1:

1
2
Input: text = "helloworld", w = 80, h = 20, fonts = [6,8,10,12,14,16,18,24,36]
Output: 6

Example 2:

1
2
Input: text = "leetcode", w = 1000, h = 50, fonts = [1,2,4]
Output: 4

Example 3:

1
2
Input: text = "easyquestion", w = 100, h = 100, fonts = [10,15,20,25]
Output: -1

Constraints:

  • 1 <= text.length <= 50000
  • text contains only lowercase English letters.
  • 1 <= w <= 10^7
  • 1 <= h <= 10^4
  • 1 <= fonts.length <= 10^5
  • 1 <= fonts[i] <= 10^5
  • fonts is sorted in ascending order and does not contain duplicates.

Solution

Method 1 – Binary Search with FontInfo API

Intuition

We want the largest font size such that the text fits within the given width and height. Since the font sizes are sorted, we can use binary search to efficiently find the maximum valid font size by querying the FontInfo API for width and height.

Approach

  1. Use binary search on the fonts array to find the largest font size that fits.
  2. For each candidate font size, check:
    • The height of any character (e.g., ‘a’) at this font size does not exceed h.
    • The total width of the text at this font size does not exceed w (sum the width of each character).
  3. If both conditions are satisfied, try a larger font; otherwise, try a smaller one.
  4. Return the largest valid font size, or -1 if none fit.

Code

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class Solution {
    public int maxFont(String text, int w, int h, int[] fonts, FontInfo fontInfo) {
        int l = 0, r = fonts.length - 1, ans = -1;
        while (l <= r) {
            int m = (l + r) / 2;
            int fontSize = fonts[m];
            if (fontInfo.getHeight(fontSize) > h) {
                r = m - 1;
                continue;
            }
            int width = 0;
            for (char c : text.toCharArray()) {
                width += fontInfo.getWidth(fontSize, c);
            }
            if (width <= w) {
                ans = fontSize;
                l = m + 1;
            } else {
                r = m - 1;
            }
        }
        return ans;
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
class Solution:
    def maxFont(self, text: str, w: int, h: int, fonts: list[int], fontInfo) -> int:
        l, r, ans = 0, len(fonts) - 1, -1
        while l <= r:
            m = (l + r) // 2
            fontSize = fonts[m]
            if fontInfo.getHeight(fontSize) > h:
                r = m - 1
                continue
            width = sum(fontInfo.getWidth(fontSize, c) for c in text)
            if width <= w:
                ans = fontSize
                l = m + 1
            else:
                r = m - 1
        return ans
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Solution {
public:
    int maxFont(string text, int w, int h, vector<int>& fonts, FontInfo &fontInfo) {
        int l = 0, r = fonts.size() - 1, ans = -1;
        while (l <= r) {
            int m = (l + r) / 2;
            int fontSize = fonts[m];
            if (fontInfo.getHeight(fontSize) > h) {
                r = m - 1;
                continue;
            }
            int width = 0;
            for (char c : text) width += fontInfo.getWidth(fontSize, c);
            if (width <= w) {
                ans = fontSize;
                l = m + 1;
            } else {
                r = m - 1;
            }
        }
        return ans;
    }
};
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
func maxFont(text string, w, h int, fonts []int, fontInfo FontInfo) int {
    l, r, ans := 0, len(fonts)-1, -1
    for l <= r {
        m := (l + r) / 2
        fontSize := fonts[m]
        if fontInfo.GetHeight(fontSize) > h {
            r = m - 1
            continue
        }
        width := 0
        for _, c := range text {
            width += fontInfo.GetWidth(fontSize, c)
        }
        if width <= w {
            ans = fontSize
            l = m + 1
        } else {
            r = m - 1
        }
    }
    return ans
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class Solution {
    fun maxFont(text: String, w: Int, h: Int, fonts: IntArray, fontInfo: FontInfo): Int {
        var l = 0
        var r = fonts.size - 1
        var ans = -1
        while (l <= r) {
            val m = (l + r) / 2
            val fontSize = fonts[m]
            if (fontInfo.getHeight(fontSize) > h) {
                r = m - 1
                continue
            }
            var width = 0
            for (c in text) width += fontInfo.getWidth(fontSize, c)
            if (width <= w) {
                ans = fontSize
                l = m + 1
            } else {
                r = m - 1
            }
        }
        return ans
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
impl Solution {
    pub fn max_font(text: String, w: i32, h: i32, fonts: Vec<i32>, font_info: &FontInfo) -> i32 {
        let (mut l, mut r, mut ans) = (0, fonts.len() as i32 - 1, -1);
        while l <= r {
            let m = (l + r) / 2;
            let font_size = fonts[m as usize];
            if font_info.get_height(font_size) > h {
                r = m - 1;
                continue;
            }
            let width: i32 = text.chars().map(|c| font_info.get_width(font_size, c)).sum();
            if width <= w {
                ans = font_size;
                l = m + 1;
            } else {
                r = m - 1;
            }
        }
        ans
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Solution {
    maxFont(text: string, w: number, h: number, fonts: number[], fontInfo: FontInfo): number {
        let l = 0, r = fonts.length - 1, ans = -1;
        while (l <= r) {
            const m = Math.floor((l + r) / 2);
            const fontSize = fonts[m];
            if (fontInfo.getHeight(fontSize) > h) {
                r = m - 1;
                continue;
            }
            let width = 0;
            for (const c of text) width += fontInfo.getWidth(fontSize, c);
            if (width <= w) {
                ans = fontSize;
                l = m + 1;
            } else {
                r = m - 1;
            }
        }
        return ans;
    }
}

Complexity

  • ⏰ Time complexity: O(len(fonts) * len(text)), as for each font size, we may check all characters in the text.
  • 🧺 Space complexity: O(1), as only a few variables are used.