LeetCode第152場周賽(Java)

這算是我第一次正式參加 LeetCode 的周賽吧。經過兩道題。意料之中(經過上次模擬能夠看出來)。總的來講,腦殼仍是不太靈光。想的有點慢。全球第一名 0:10:19 就所有經過。。。感受個人智商被狠狠的摁在地上摩擦了。java

參考:huntersjmweb


5175. 構建迴文串檢測

我第一次提交的直接 TLE。而後就沒有而後了。數組

TLE 代碼的思路(能夠不看):svg

  • 定義一個 int 型的 notParesNum 保存字母個數爲奇數的字母的數量。
  • 每次檢測,將 [left, right] 字串取出,統計裏面每種字母的個數,若是個數是奇數,那麼將 notParesNum 數量加 1。
  • 統計結束後,檢查 notParesNum / 2k的關係。若是是大於,那麼就是 false,不然就是 true

改進一次後的思路:編碼

  • 在循環過程當中就檢查 notParesNum / 2k的關係。若是是 false,直接 continue

依然超時了。而後就沒時間了,我就沒想了。spa

正確思路:code

  • 先要進行預處理。定義 int 型二維數組 charNum[length + 1][26]。其中 length 爲字符串 s 的長度。而且 charNum[0] 不保存數據。
  • 每次檢測的時候,先檢查 k 的值,若是大於等於 25,那麼必定能夠將子串替換成迴文串,由於最多 26 種字母。(不超時的關鍵點
  • 再檢測子串的長度的一半是否超過 k,若是不超過,那麼必定能夠將子串替換成迴文串。(次關鍵點
  • 過濾上面兩部分後,就來最後一種狀況,計算 charNum[right]charNum[left] 的差值,統計字母個數爲奇數的字母個數 notParesNum
    • 統計差值的時候要注意 26 個字母中,有一個字母的個數要額外加 1。具體見代碼。
  • 統計結束後,檢查 notParesNum / 2k 的關係。若是是大於,那麼就是 false,不然就是 true

運算符優先級從高到低順序:+ -<< >>< > <= >=||=xml

代碼以下:blog

class Solution {
	public List<Boolean> canMakePaliQueries(String s,
											int[][] queries) {
		// 一、預處理,統計每種字母的個數
		int length = s.length();// 字母個數
		int[][] charNum = new int[length + 1][26];// 保存個數
		char[] arrS = s.toCharArray();
		for (int i = 0; i < length; ++i) {
			int ch = arrS[i] - 'a';
			charNum[i + 1] = Arrays.copyOf(charNum[i], 26);// 其它字母個數相同
			++charNum[i + 1][ch];// 字母arrS[i]個數加 1
		}

		// 二、保存結果
		List<Boolean> ans = new ArrayList<>();

		// 三、檢測每一個子串是否能夠變成迴文串
		for (int[] querie : queries) {
			int left = querie[0];
			int right = querie[1];
			int k = querie[2];

			// 26個字母,最多25次就能替換成迴文串,或者子串長度的一半不超過k
			if (k >= 25 || (right - left + 1) >> 1 <= k) {
				ans.add(true);// 必定能用不超過k次替換就能變成迴文串
				continue;
			}

			// 超過k次的話,就檢查非成對字母的個數的一半是否超過k
			int notParesNum = 0;// 非成對字母個數
			int ch = arrS[left] - 'a';// 左邊界字母

			// 統計子串中每一個字母的個數,若是個數爲奇數,notParesNum加1
			for (int i = 0; i < 26; ++i) {
				// 因爲是從charNum[1]開始保存數據,故下標要加1
				int num = charNum[right + 1][i] - charNum[left + 1][i];

				if (i == ch) {// i是左邊界字母
					++num;// 個數加1,由於上一步計算差值的時候沒有加上這一個
				}

				if (0 != (num & 1)) {// 當前字母個數爲奇數
					++notParesNum;// 非對稱字母個數加1
				}
			}

			// 非對稱的字母能夠經過改變變成同一字母,故除以2
			if (notParesNum >> 1 > k) {// 替換次數超過k次
				ans.add(false);
			} else {// 替換次數不超過k次
				ans.add(true);
			}
		}

		return ans;// 返回結果
	}
}

提交結果:
5175token


5176. 猜字謎

什麼題目,一直超時超時。參考了別人的代碼,用它的代碼提交了 七、8 次,只有一次經過了。。就一句話解釋算了。

int 型數保存字符串的字母狀況,低 26 位,每一位保存對應位的字母是否存在,1 表示存在,0 表示不存在。

運算符優先級從高到低順序:+ -<< >>==&||=

代碼以下:

class Solution {
    public List<Integer> findNumOfValidWords(	String[] words,
                                                String[] puzzles) {
        int[] codeWords = new int[words.length];// 保存編碼後的值
        for (int i = 0; i < words.length; ++i) {
            codeWords[i] = code(words[i]);// 給每一個單詞編碼
        }

        List<Integer> ans = new ArrayList<>();
        for (String puzzle : puzzles) {// 遍歷全部謎面
            int codePuzzle = code(puzzle);// 給謎面編碼
            int count = 0;// 謎底個數
            for (int value : codeWords) {// 遍歷全部單詞的編碼
                if ((codePuzzle & value) == value) {// 單詞中字母全都在謎面中
                    if ((value >> puzzle.charAt(0) - 'a' & 1) == 1) {
                        ++count;// 單詞包含謎面首字母,謎底個數加1
                    }
                }
            }
            ans.add(count);// 個數添加到結果中
        }
        return ans;// 返回結果
    }

    // 整數的低26位保存字符串的字母信息,包含字母,對應位置1
    private int code(String str) {// 將字符串編碼成整數
        int num = 0;
        int length = str.length();
        for (int i = 0; i < length; ++i) {
            num |= 1 << str.charAt(i) - 'a';
        }
        return num;// 返回編碼後的值,低26位,每一位表明一個字母
    }
}

提交結果:
5176

相關文章
相關標籤/搜索