找出适应屏幕的最大字号

Submission

运行时间: 412 ms

内存: 27.8 MB

# """
# This is FontInfo's API interface.
# You should not implement it, or speculate about its implementation
# """
#class FontInfo(object):
#    Return the width of char ch when fontSize is used.
#    def getWidth(self, fontSize, ch):
#        """
#        :type fontSize: int
#        :type ch: char
#        :rtype int
#        """
# 
#    def getHeight(self, fontSize):
#        """
#        :type fontSize: int
#        :rtype int
#        """

from collections import Counter


class Solution:
    def maxFont(self, text: str, w: int, h: int, fonts: List[int], fontInfo : 'FontInfo') -> int:

        @lru_cache(None)
        def check(x):
            f = fonts[x]
            if fontInfo.getHeight(f) > h:
                return False
            width = 0
            for ch in cnt:
                width += cnt[ch]*fontInfo.getWidth(f, ch)
                if width > w:
                    return False
            return True

        cnt = Counter(text)
        m = len(fonts)
        i = 0
        j = m - 1
        while i < j - 1:
            mid = i + (j - i) // 2
            if check(mid):
                i = mid
            else:
                j = mid
        if check(j):
            return fonts[j]
        if check(i):
            return fonts[i]
        return -1

        

Explain

该题解利用二分查找来解决找出适应屏幕的最大字号问题。首先,使用一个辅助函数 `check(x)` 来判断给定字号是否能使所有文字适应屏幕宽度和高度。如果当前字号的高度超过屏幕高度或者文字总宽度超过屏幕宽度,则该字号不合适。通过使用二分查找,我们可以有效地找到最大合适的字号。检查函数被缓存,以优化重复计算。

时间复杂度: O(n * log m)

空间复杂度: O(u + m)

# 使用 FontInfo 的 API 接口,不实现具体的函数
# class FontInfo(object):
#     def getWidth(self, fontSize, ch):
#     def getHeight(self, fontSize):

from collections import Counter
from functools import lru_cache


class Solution:
    def maxFont(self, text: str, w: int, h: int, fonts: List[int], fontInfo : 'FontInfo') -> int:

        @lru_cache(None)
        def check(x):
            f = fonts[x]
            if fontInfo.getHeight(f) > h:
                return False  # 字号高度超过屏幕
            width = 0
            for ch in cnt:
                width += cnt[ch]*fontInfo.getWidth(f, ch)
                if width > w:
                    return False  # 文字总宽度超过屏幕宽度
            return True

        cnt = Counter(text)  # 统计每个字符的出现次数
        m = len(fonts)
        i = 0
        j = m - 1
        while i < j - 1:
            mid = i + (j - i) // 2
            if check(mid):
                i = mid
            else:
                j = mid
        if check(j):
            return fonts[j]
        if check(i):
            return fonts[i]
        return -1  # 如果没有合适的字号,返回 -1

Explore

选择`i + (j - i) // 2`作为计算中点的方式是为了防止`i`和`j`的值非常大时,直接相加导致整数溢出。虽然在Python中整数类型可以自动处理大数,但在其他编程语言如Java或C++中,整数类型有固定的大小限制,直接相加可能会超出该类型的最大值。因此,`i + (j - i) // 2`是一种更安全的方法,适用于多种编程环境。

在本题中,使用`i < j - 1`作为循环条件是为了确保循环退出时,`i`和`j`之间最多只有一个元素,这样可以在循环外部对这两个元素进行额外的检查,以确定哪个字号确实适合。这与常见的`i <= j`条件不同,后者通常会在找到目标或条件不满足时直接结束循环。使用`i < j - 1`能更精确地控制循环的结束条件,特别是在需要最后进一步判断的场景中非常有用。

在二分查找结束后,`i`和`j`的位置可能非常接近但不一定精确指向满足条件的最大字号。因此,需要分别检查`i`和`j`的位置以确定哪个字号实际上可以适应屏幕。这种方法确保了即使在循环条件使得`i`和`j`相邻时,我们也能通过额外检查找到确切的、最大的适应字号。

在Python中,整数类型是动态的,可以自动处理较大的数值而不会发生溢出。这意味着即使字符宽度累计的值很大,Python仍然可以正确处理。在设计算法时,不需要特别考虑整数溢出的问题,除非在使用固定整数大小的编程语言。在那种情况下,可能需要引入额外的逻辑来检测和处理潜在的溢出情况。