徒手挖地球二四周目
NO.225 用隊列實現棧 簡單
思路一:使用隊列API 其實沒有太搞明白這個題目的意思。。。leetcode打卡活動第一天題目。
主要是push()方法每次將新加入元素x之前的元素都按序出隊並重新入隊,這樣新元素x就在隊頭。
然後pop()、top()、empty()直接調用隊列API就好。。。
public class MyStack {
Queue<Integer> queue;
/** Initialize your data structure here. */
public MyStack() {
this.queue=new LinkedList<>();
}
/** Push element x onto stack. */
public void push(int x) {
queue.add(x);
for (int i = 1; i < queue.size(); i++) {
queue.add(queue.remove());
}
}
/** Removes the element on top of the stack and returns that element. */
public int pop() {
return queue.poll();
}
/** Get the top element. */
public int top() {
return queue.peek();
}
/** Returns whether the stack is empty. */
public boolean empty() {
return queue.isEmpty();
}
}
時間複雜度:push()是O(n),其餘三個方法時O(1)
NO.53 最大子序和 簡單
思路一:動態規劃法 分析dp那就要先分析dp[i]的含義:以第i元素結尾的最大序列和。
初始化:dp[0]以第0號元素結尾的序列只有nums[0]本身,所以dp[0]=nums[0]
。
轉移方程:dp[i]=Max(dp[i-1]+nums[i],nums[i])
,因爲dp[i-1]是以i-1爲結尾的序列和中的最大值,所以我們想找nums[i]結尾的最大序列和只需要比較"前一個最大序列和+nums[i]“和"nums[i]”。舉個例子:
public int maxSubArray(int[] nums) {
if (nums==null||nums.length==0)return 0;
int[] dp=new int[nums.length];
//初始化
dp[0]=nums[0];
//填寫dp數組同時用max記錄當前最大的序列和
int max=dp[0];
for (int i = 1; i < nums.length; i++) {
dp[i]=Math.max(nums[i],dp[i-1]+nums[i]);
max=Math.max(max,dp[i]);
}
return max;
}
經過思考不難發現,並不需要開闢一個數組來保存每一個子序和。每次填寫只需要關心上一次狀態值即可,且每個狀態值只需要使用一次。所以我們可以用一個int變量代替dp數組即可:
public int maxSubArray(int[] nums) {
if (nums==null||nums.length==0)return 0;
//初始化
int dp=nums[0];
//更新當前i結尾的最大序列和同時用max記錄最大的序列和
int max=dp;
for (int i = 1; i < nums.length; i++) {
dp=Math.max(nums[i],dp+nums[i]);
max=Math.max(max,dp);
}
return max;
}
時間複雜度:O(n)
NO.206 翻轉鏈表 簡單
本題是K個一組翻轉鏈表這道題的其中一步,學習完本題可以趁熱打鐵學習NO.25,題解參考徒手挖地球十八週目。
思路一:迭代實現 翻轉鏈表需要三個"指針":pre指向前驅、curr指向當前節點、next指向後繼。
過程比較簡單,自己模擬一遍就好了:
public ListNode reverseList(ListNode head) {
if (head==null||head.next==null)return head;
ListNode pre=null,curr=head;
while (curr!= null) {
ListNode next=curr.next;
curr.next=pre;
pre=curr;
curr=next;
}
return pre;
}
時間複雜度:O(n)
思路二:遞歸實現 每層遞歸返回已經翻轉好的部分。
public ListNode reverseList(ListNode head) {
if (head==null||head.next==null)return head;
ListNode pre=reverseList(head.next);
head.next.next=head;
head.next=null;
return pre;
}
時間複雜度:O(n)
NO.54 螺旋矩陣 中等
思路一:按層模擬法 從[0][0]開始模擬順時針一層一層的遍歷所有元素。
計算層數count:(Min(row,col)+1)/2
,因爲每次最多有兩行兩列組成,最少由一行或一列組成。
遍歷每一層curr即[0,count)
,每層有四次"轉彎":
- 每一層先從左到右遍歷一行,即
for(i=curr;i<col-curr;i++)matrix[curr][i]
。 - 再從上到下遍歷一列,即
for(i=curr+1;i<row-curr;i++)matrix[i][col-1-curr]
。 - 再從右到左遍歷一行,即
for(i=col-1-curr-1;i>=curr;i--)matrix[row-1-i][i]
。 - 最後從下到上遍歷一列,即
for(i=row-1-curr-1;i>=curr+1;i--)matrix[i][curr]
。
ps:每一層除了第一行是遍歷一整行元素,其餘三部分都需要注意不要重複遍歷"拐點"元素。
上述是常規層(兩行兩列)的遍歷;如果只有一行,從右向左遍歷時會重複遍歷;如果只有一列,從下向上遍歷時會重複遍歷,如何解決這個問題?
答:只有一行或只有一列時,不進行右向左或下向上的遍歷即可。如何判斷?row-1-curr==curr
說明當前層只有一行;col-1-curr==curr
說明當前層只有一列。
public List<Integer> spiralOrder(int[][] matrix) {
List<Integer> res=new ArrayList<>();
if (matrix==null||matrix.length==0)return res;
int row = matrix.length,col=matrix[0].length;
//計算有多少層
int count=(Math.min(row,col)+1)/2;
//當前層
int curr=0;
//遍歷每一層
for (;curr<count;curr++){
//從左向右
for (int i = curr; i < col - curr; i++) {
res.add(matrix[curr][i]);
}
//從上到下
for (int i = curr+1; i < row-curr; i++) {
res.add(matrix[i][col-1-curr]);
}
//從右到左
for (int i = col-1-curr-1; i >= curr&&(row-1-curr!=curr); i--) {
res.add(matrix[row-1-curr][i]);
}
//從下到上
for (int i = row-1-curr-1; i >= curr+1&&(col-1-curr!=curr); i--) {
res.add(matrix[i][curr]);
}
}
return res;
}
時間複雜度:O(n)
本人菜鳥,有錯誤請告知,感激不盡!