LeetCode刷題記錄(四)
LeetCode刷題記錄(四)
1、陣列拆分 I
題目:
我的思路:
這一題我的思路分為兩步:首先要將這個陣列中的元素進行排序,使其成為一個有序陣列,然後挑選出其中第奇數個元素,將它們相加的和就是結果。
為什麼是第奇數個元素相加呢?根據題目中要求,要選出兩兩組合中較小的元素相加然後得到最大的總和,所以我們就要使兩兩組合中較小的那個元素儘量大,因為已經先對這個陣列進行了排序,所以這2n個數中值最大的元素就是第2n個數,它是不可能被選出來的,那麼比2n小但是比其他的元素都大的數是第2n-1個數,因此它可以被選中,以此類推,我們繼續從剩下的2n-2個元素中繼續挑選較大的元素,都是奇數索引所對應的元素。
按照這個思路實現的程式碼如下:
class Solution {
public int arrayPairSum(int[] nums) {
//1、先排序
for (int i = 1; i < nums.length; i++) {
int get = nums[i];
int left = 0;
int right = i - 1;
while (left <= right)
{
int mid = (left + right) / 2;
if (nums[mid] > get)
right = mid - 1;
else
left = mid + 1;
}
for (int j = i - 1; j >= left; j--)
{
nums[j + 1] = nums[j];
}
nums[left] = get;
}
//2、獲取第奇數個數相加
int rslt = 0;
for(int a = 0; a < nums.length; a = a + 2) {
rslt += nums[a];
}
return rslt;
}
}
反思:
這一題我是自己寫的一個排序方法,可能效率不高,其實可以呼叫Java提供的陣列排序方法。
2、兩數之和 II - 輸入有序陣列
題目:
我的思路:
- 因為這個陣列是升序排列的,所以可以定義兩個指標i和j分別指向陣列的第一個元素和最後一個元素;
- 判斷target減去j指向的元素,得到的結果如果小於i指向的元素,那麼說明j指向的元素較大,因此j要向前移,如果得到的結果大於i指向的元素,說明i指向的元素較小,i要向後移,這樣移動i和j直到得到結果為止。
按照這個思路實現的程式碼如下:
class Solution {
public int[] twoSum(int[] numbers, int target) {
int i = 0, j = numbers.length - 1;
int[] rslt = new int[2];
while(i < j) {
if(target - numbers[j] < numbers[i]) {
//1、j指向的值較大,j向前移
j--;
} else if(target - numbers[j] > numbers[i]) {
//2、i指向的值較小,i向後移
i++;
} else {
rslt[0] = i + 1;
rslt[1] = j + 1;
break;
}
}
return rslt;
}
}
3、移除元素
題目:
我的思路:
- 因為題目要求要原地移除元素,所以不能定義新的陣列,可以定義兩個指標i和j分別指向陣列第一個元素和最後一個元素;
- 從前向後遍歷陣列,如果i指向的元素和要移除的元素值相同,那麼替換i指向元素的值為j指向的元素,同時j指標向前移動一位,否則直接將i指標向後移動一位;
- 這樣移動i和j指標直到兩個指標相遇。
按照這個思路實現的程式碼如下:
class Solution {
public int removeElement(int[] nums, int val) {
if(nums == null || nums.length == 0) {
return 0;
}
if(nums.length == 1 && nums[0] == val) {
return 0;
} else if(nums.length == 1 && nums[0] != val) {
return 1;
}
int i =0, j = nums.length - 1;
while(i <= j) {
if(nums[i] != val) {
i++;
} else {
nums[i] = nums[j];
j--;
}
}
return i;
}
}
4、最大連續1的個數
題目:
我的思路:
- 這一題也可以定義兩個指標i和j,它們屬於快慢指標,一開始都是指向的是陣列的第一個元素,由j指標依次遍歷整個陣列;
- 可以判斷i指標指向的元素和j指標指向的元素,如果都是1的話,那麼可以得到連續1的個數,並且與最大長度進行比較,如果大於最大長度,那麼可以得到最新的一個最大長度,如果i和j的值都是0的話,i指標也要向後移動一位,如果j指標為0而i指標為1的話,那麼i指標直接指向j指標指向的下一個元素即可。
按照這個思路實現的程式碼如下:
class Solution {
public int findMaxConsecutiveOnes(int[] nums) {
int max = 0;
int i = 0, j = 0;
for(; j < nums.length; j++) {
int len = 0;
if(nums[j] == 1 && nums[i] == 1) {
len = j - i + 1;
if(len > max) {
max = len;
}
} else if(nums[j] == 0 && nums[i] == 0) {
i++;
} else if(nums[j] == 0 && nums[i] == 1) {
i = j + 1;
}
}
return max;
}
}
5、長度最小的子陣列
題目:
我的思路:
這一題我的思路可能時間複雜度會比較高,仍然定義快慢指標i和j,一開始都是指向陣列的第一個元素,由j依次向後遍歷,計算i到j值的和,如果和大於等於s,那麼向後移動i,再計算i到j值的和,這樣依次計算直到最後得到最小長度。
按照這個思路實現的程式碼如下:
class Solution {
public int minSubArrayLen(int s, int[] nums) {
if(nums == null || nums.length == 0) {
return 0;
}
int rslt = nums.length, sum = 0;
int i = 0, j = 0;
//1、定義一個布林值用於判斷是否得到結果
boolean getRslt = false;
//2、分兩種迴圈,一種是沒有得到結果且j遍歷到最後,另一種是已經獲取到結果並且i還沒遍歷到最後
while((!getRslt && j <= nums.length - 1) || (getRslt && i < nums.length)) {
for(int m = i; m <= j; m++) {
sum += nums[m];
}
if(sum >= s) {
//3、數字和大於現有的最小值則將最小值賦予rslt,i遞增
if(j - i + 1 < rslt) {
rslt = j - i + 1;
}
i++;
getRslt = true;
} else if(j < nums.length){
j++;
//4、如果j遍歷到最後了但是已經得到和大於s的情況,則j在最後不變,i遞增
//防止{1,2,3} 4死迴圈
if(j == nums.length && getRslt) {
i++;
j = nums.length - 1;
}
} else if(getRslt && i < nums.length) {
//5、遞增i用於跳出迴圈
i++;
}
sum = 0;
}
if(getRslt) {
return rslt;
} else {
return 0;
}
}
}
反思:
這一題思路比較清晰簡單,但是實際編寫過程中遇到了一個問題。
一開始我的迴圈條件沒有這麼複雜,只是判斷j是否遍歷到最後了,如果遍歷到最後直接跳出迴圈,這就可能存在一個問題,例如陣列為[1, 2, 3],s為4,那麼j遍歷到最後的時候才得到1+2+3>4,這樣直接跳出迴圈得到的子陣列的長度為3,實際上的結果應該是2+3>4長度最小子陣列長度為2,j遍歷到最後直接跳出迴圈導致i無法再向後移動。因此我定義了一個布林值變數用於控制是否得到結果,如果j遍歷到最後並且得到了結果,那麼j保持不變,i繼續向後移動。而跳出迴圈的條件又分為兩個,一個是沒有得到最終的結果,但是j已經遍歷到最後,另一個是已經得到了最終的結果,i也遍歷到最後。
從最終的解法可以看出來,這樣做時間複雜度是很高的,特別是對於已經得到結果仍然要等到i遍歷到最後的情況,具體優化的方法還在摸索中。
6、旋轉陣列
題目:
我的思路:
這一題因為也是要求使用原地演算法,所以不能定義額外的陣列。我設計了一個迴圈,每次迴圈也就是向右移動一次陣列。如果向右移動一次陣列,陣列的最後一個值就要移動到陣列的第一位,因此可以設定一個臨時變數儲存陣列的最後一個值,等到陣列其他位數全部移動完了之後再將原陣列最後的一個值設定到新陣列的第一位。
按照這個思路實現的程式碼如下:
class Solution {
public void rotate(int[] nums, int k) {
if(nums == null || nums.length == 0 || nums.length == 1) {
return;
}
//1、對k取模,這是為了防止出現k大於nums長度的情況
//如果k大於nums的長度,那麼實際上移動的位置就是k%nums.length位
if(k >= nums.length) {
k = k % nums.length;
}
//2、每次向右移動一次陣列,直到移動的步數
for(int i = 0; i < k; i++) {
int lastNum = nums[nums.length - 1];
//3、將第1位到length - 1位向右移動一位
for(int j = nums.length - 2; j >= 0; j--) {
int tmp = nums[j];
nums[j + 1] = tmp;
}
//4、將第0位置為原陣列的最後一個數
nums[0] = lastNum;
}
}
}
反思:
這種實現方式因為每次都要移動全部的陣列,所以時間複雜度也是比較高的,以後還要繼續研究一下是否有更高效的方式。
7、楊輝三角 II
題目:
我的思路:
這一題我的思路和第三篇中介紹的《楊輝三角》是一樣的,只是最後返回第k行資料即可,題目中進階要求能否優化演算法到O(k)的空間複雜度暫時還未想到好的方式,以後有新的解法可以繼續更新。
按照這個思路實現的程式碼如下:
class Solution {
public List<Integer> getRow(int rowIndex) {
List<List<Integer>> rslt = new ArrayList<List<Integer>>();
List<Integer> row;
for(int i = 0; i <= rowIndex; i++) {
row = new ArrayList<Integer>();
if(i == 0) {
row.add(1);
rslt.add(row);
} else {
for(int j = 0; j <= i; j++) {
if(j - 1 < 0) {
row.add(0 + rslt.get(i - 1).get(j));
} else if(j >= rslt.get(i - 1).size()) {
row.add(rslt.get(i - 1).get(j - 1) + 0);
} else {
row.add(rslt.get(i - 1).get(j - 1) + rslt.get(i - 1).get(j));
}
}
rslt.add(row);
}
}
return rslt.get(rowIndex);
}
}
8、翻轉字串裡的單詞
題目:
我的思路:
- 先將字串通過spilt()方法以空格進行分割,得到一個字串陣列;
- 然後使用雙指標的方式翻轉字串陣列中的單詞,在翻轉字串陣列中單詞的同時要剔除空格;
- 遍歷字串陣列拼接一個新的字串。
按照這個思路實現的程式碼如下:
public class Solution {
public String reverseWords(String s) {
if(s == null) {
return null;
}
if(s.trim().equals("")) {
return "";
}
//1、先剔除原有字串中前後多餘的空格,然後以空格分割字串得到字串陣列
String[] words = s.trim().split(" ");
//2、翻轉字串陣列
for(int i = 0, j = words.length - 1; i < j;i++, j--) {
String tmp = words[i];
words[i] = words[j].trim();
words[j] = tmp.trim();
}
//3、拼接得到新的字串
StringBuffer sb = new StringBuffer();
for(int i = 0; i < words.length; i++) {
if(!"".equals(words[i].trim())) {
sb.append(words[i] + " ");
}
}
return sb.toString().trim();
}
}
9、反轉字串中的單詞 III
題目:
我的思路:
- 首先使用spilt()方法將字串以空格進行分割,獲得字串陣列;
- 將字串陣列中每個字串進行翻轉,先將字串轉換為字元陣列,然後使用雙指標的方式進行翻轉;
- 將翻轉後的字串陣列重新拼接成新的字串。
按照這個思路實現的程式碼如下:
class Solution {
public String reverseWords(String s) {
if(null == s) {
return null;
}
if("".equals(s.trim())) {
return "";
}
//1、將字串以空格進行分割
String[] words = s.split(" ");
StringBuffer sb = new StringBuffer();
for(String word : words) {
sb.append(reverseOneWord(word) + " ");
}
return sb.toString().trim();
}
//2、單獨寫一個方法用於翻轉分割後的每個字串
private String reverseOneWord(String word) {
char[] chars = word.toCharArray();
StringBuffer sb = new StringBuffer();
for(int i = 0, j = chars.length - 1; i < j; i++, j--) {
char tmp = chars[i];
chars[i] = chars[j];
chars[j] = tmp;
}
sb.append(chars);
return sb.toString();
}
}
10、刪除排序陣列中的重複項
題目:
我的思路:
這一題仍然是要求原地刪除陣列中的重複項,也就是說仍然不能新定義陣列。
我依然使用快慢指標的方式來解決,定義兩個指標i和n,i用於從陣列第一位開始向後遍歷,而n一開始指向i的後一位,即陣列第二位。i在遍歷陣列的時候要判斷當前值在陣列中是否重複,如果重複了,i向後移一位直到遇到不重複的值為止,然後將第n位的值替換為不重複的值,n向後移動一位,這樣迴圈直到得到最終結果。
按照這個思路實現的程式碼如下:
class Solution {
public int removeDuplicates(int[] nums) {
if(nums == null || nums.length == 0) {
return 0;
}
if(nums.length == 1) {
return 1;
}
int tmp = nums[0];
int n = 1;
/**
1、使用快慢兩個指標,快指標i遍歷陣列每一個數,並使用一個臨時值記錄陣列的每個重複數字
*/
for(int i = 1; i < nums.length;) {
//2、用m記錄i的初始位置
int m = i
相關推薦
LeetCode刷題記錄(四)
LeetCode刷題記錄(四)
1、陣列拆分 I
題目:
我的思路:
這一題我的思路分為兩步:首先要將這個陣列中的元素進行排序,使其成為一個有序陣列,然後挑選出其中第奇數個元素,將它們相加的和就是結果。
為什麼是第奇數個元素相加呢?根據題目中要求,要選出兩兩組合
LeetCode刷題記錄(三)
LeetCode刷題記錄(三)
1、螺旋矩陣
題目:
我的思路:
我將獲取螺旋矩陣的過程分為四步:先從左往右遍歷矩陣的值,到最右之後再從上往下遍歷,到最下面之後再從右往左遍歷,到最左側之後再從下往上遍歷,這樣依次迴圈,直到遍歷到最後一個值;
根據這個思
LeetCode刷題記錄(二)
LeetCode刷題記錄(二)
繼續陣列和字串卡片的題目,這一篇主要介紹一道二維陣列相關的題目。
1、對角線遍歷
題目:
我的思路:
這一題我的思路比較複雜,我先觀察幾種型別的二維陣列
1、 M=N型別的二維陣列,例如:
[1, 2, 3]
LeetCode刷題記錄(一)
LeetCode刷題記錄(一)
最近開始在LeetCode上面做題,想想應該做一個記錄,以便以後看到類似的問題及時查閱,同時也能夠將做題時的思路記錄下來,將這些思路整理歸納,形成一套我自己的解題思路。當然,演算法題只做一次是不夠的,需要多次的練習,可能每次的想法都不太一樣,在這裡我只
LeetCode刷題記錄(五)
LeetCode刷題記錄(五)
今天開始佇列&棧卡片的學習。
1、設計迴圈佇列
題目: 我的思路:
迴圈佇列的工作原理可以參考LeetCode上的介紹,從介紹中我們可以看到:
可以定義一個數組來儲存佇列中的元素,迴圈佇列定義了兩個指標,一個指標指向
LeetCode刷題記錄——(加一)
題目描述
給定一個由整陣列成的非空陣列所表示的非負整數,在該數的基礎上加一。
最高位數字存放在陣列的首位, 陣列中每個元素只儲存一個數字。
你可以假設除了整數 0 之外,這個整數不會以零開頭。
示例 1:
輸入: [1,2,3] 輸出: [1,2,4] 解釋:
leetcode刷題記錄(買賣股票的最佳時機系列問題)
開始逐步拾起C++,故以後的刷題,全用python和C++兩種語言實現。
一、買賣股票的最佳時機 I
給定一個數組,它的第 i 個元素是一支給定股票第 i 天的價格。
如果你最多隻允許完成一筆交易(即買入和賣出一支股票),設計一個演算法來計算你所能獲取的最大利潤。
注
leetcode刷題記錄(949、367、374)
2018.12.25 leetcode 刷題總結
題號:949
給定一個由 4 位數字組成的陣列,返回可以設定的符合 24 小時制的最大時間。 最小的 24 小時制時間是 00:00,而最大的是 23:59。從 00:00 (午夜)開始算起,過得越久,時間越大。 以長度為
LeetCode 刷題記錄(8,9,10)—Java語言
8. 字串轉整數 (atoi)
題目
實現 atoi,將字串轉為整數。
在找到第一個非空字元之前,需要移除掉字串中的空格字元。如果第一個非空字元是正號或負號,選取該符號,並將其與後面儘可能多的連續的數字組合起來,這部分字元即為整數的值。如果第一個非空字
LeetCode刷題記錄(第一天)
Jewels and Stones原題目:You're given strings J representing the types of stones that are jewels, and S representing the stones you have. Eac
LeetCode 刷題記錄(5,6,7)—Java語言
5. 最長迴文子串
給定一個字串 s,找到 s 中最長的迴文子串。你可以假設 s 的最大長度為1000。
示例 1:
輸入: “babad”
輸出: “bab”
注意: “aba”也是一個有效答案。
示例 2:
輸入: “cbbd”
輸出: “b
LeetCode刷題記錄(第五天)
Trapping Rain Water原題目:Given n non-negative integers representing an elevation map where the width of each bar is 1, compute how much wate
LeetCode 刷題記錄(19、20)—Java語言
19. 刪除連結串列的倒數第N個節點
題目
給定一個連結串列,刪除連結串列的倒數第 n 個節點,並且返回連結串列的頭結點。
示例:
給定一個連結串列: 1->2->3->4->5, 和 n = 2.
當刪除了倒數第二個節點後,連
LeetCode刷題記錄(第六天)
Swap Salary這道題竟然是一個sql題,雖然經常寫sql和看關於mysql的效能優化,但是我發現一個大問題,我都白學來。。。。題目:Given a table salary, such as the one below, that has m=male and f=f
leetcode刷題總結(1)
solution 遍歷 AC 復雜度 刷題 may example AR 記錄 1、Two Sum
Given an array of integers, return indices of the two numbers such that they add up to
LeetCode刷題實戰(二)
題2描述:
You are given two non-empty linked lists representing two non-negative integers. The digits are stored in reverse order and each of
LeetCode刷題筆記(一)
問題一:兩數相加
給定兩個非空連結串列來表示兩個非負整數,位數按照逆序方式儲存,它們的每個節點只儲存單個數字,將兩數相加返回一個新的連結串列。
例項:
輸入:(2 -> 4->3) + (5->6->4)
輸出:7 -> 0 - >
LeetCode刷題筆記(二)
4. 兩個排序陣列的中位數
給定兩個大小為 m 和 n 的有序陣列 nums1 和 nums2 。
請找出這兩個有序陣列的中位數。要求演算法的時間複雜度為 O(log (m+n)) 。
你可以假設 nums1 和 nums2 不同時為空。
示例 1:
nums1 =
LeetCode刷題實戰(13):Roman to Interger
題目描述:
Roman numerals are represented by seven different symbols: I, V, X, L, C, D and M.
Symbol Value
I 1
V
Leetcode刷題python(3)
各位相加
#題目
給定一個非負整數 num,反覆將各個位上的數字相加,直到結果為一位數。
示例:
輸入: 38
輸出: 2
解釋: 各位相加的過程為:3 + 8 = 11, 1 + 1 = 2。 由於 2 是一位數,所以返回 2。
進階:
你可以不使用迴圈或者遞