王廷瑋|數位醫療|智慧醫療: 8月 2024 WFU

2024年8月27日 星期二

227. Basic Calculator II

227. Basic Calculator II


給定一個表示算式的字串 s,計算該算式的結果並返回其值。

整數除法應該向零截斷。

你可以假設給定的算式總是有效的。所有中間結果都會在 [-2³¹, 2³¹ - 1] 的範圍內。

注意:你不允許使用任何內建函數來直接計算字符串中的數學表達式,例如 eval()

範例:

輸入: s = "3+2*2"
輸出: 7


Python


class Solution:
def calculate(self, s: str) -> int:
def update(op, v):
if op == "+": stack.append(v)
if op == "-": stack.append(-v)
if op == "*": stack.append(stack.pop() * v)
if op == "/": stack.append(int(stack.pop() / v))
it, num, stack, sign = 0, 0, [], "+"
while it < len(s):
if s[it].isdigit():
num = num * 10 + int(s[it])
elif s[it] in "+-*/":
update(sign, num)
num, sign = 0, s[it]
elif s[it] == "(":
num, j = self.calculate(s[it + 1:])
it = it + j
elif s[it] == ")":
update(sign, num)
return sum(stack), it + 1
it += 1
update(sign, num)
return sum(stack)

19.89MB, 125ms


C++


class Solution {
public:
int calculate(string s) {
int length = s.length();
if (length == 0) return 0;
int currentNumber = 0, lastNumber = 0, result = 0;
char sign = '+';
for (int i = 0; i < length; i++) {
char currentChar = s[i];
if (isdigit(currentChar)) {
currentNumber = (currentNumber * 10) + (currentChar - '0');
}
if (!isdigit(currentChar) && !iswspace(currentChar) || i == length - 1) {
if (sign == '+' || sign == '-') {
result += lastNumber;
lastNumber = (sign == '+') ? currentNumber : -currentNumber;
} else if (sign == '*') {
lastNumber = lastNumber * currentNumber;
} else if (sign == '/') {
lastNumber = lastNumber / currentNumber;
}
sign = currentChar;
currentNumber = 0;
}
}
result += lastNumber;
return result;
}
};

11.04MB, 18ms


Javascript


/**
* @param {string} s
* @return {number}
*/
var calculate = function(s) {
// Remove all white spaces from the string
s = s.replace(/\s+/g, '');

// Initialize a stack to keep track of numbers and operations
let stack = [];
let currentNumber = 0;
let operation = '+'; // Start with an addition operation by default

for (let i = 0; i < s.length; i++) {
let currentChar = s[i];

if (!isNaN(currentChar)) {
// Build the current number
currentNumber = currentNumber * 10 + parseInt(currentChar);
}

// If the current character is an operator or we're at the end of the string
if (isNaN(currentChar) || i === s.length - 1) {
if (operation === '+') {
stack.push(currentNumber);
} else if (operation === '-') {
stack.push(-currentNumber);
} else if (operation === '*') {
stack.push(stack.pop() * currentNumber);
} else if (operation === '/') {
stack.push(Math.trunc(stack.pop() / currentNumber));
}
// Update the operation and reset currentNumber
operation = currentChar;
currentNumber = 0;
}
}

// Sum up all the numbers in the stack to get the final result
return stack.reduce((a, b) => a + b, 0);
};

58.36MB, 92ms


226. Invert Binary Tree

226. Invert Binary Tree


給定一個二叉樹的根節點,反轉這棵樹,並返回其根節點。

範例 1:

輸入: root = [4,2,7,1,3,6,9]
輸出: [4,7,2,9,6,3,1]



Python


# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def invertTree(self, root: Optional[TreeNode]) -> Optional[TreeNode]:
if not root:
return None
# Swap the left and right children
root.left, root.right = root.right, root.left
# Recursively invert the left and right subtrees
self.invertTree(root.left)
self.invertTree(root.right)
return root

16.52MB, 34ms


C++


/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
TreeNode* invertTree(TreeNode* root) {
if (root == nullptr) {
return nullptr;
}
// Swap the left and right children
TreeNode* temp = root->left;
root->left = root->right;
root->right = temp;
// Recursively invert the left and right subtrees
invertTree(root->left);
invertTree(root->right);
return root;
}
};

11.88MB, 5ms


Javascript


/**
* Definition for a binary tree node.
* function TreeNode(val, left, right) {
* this.val = (val===undefined ? 0 : val)
* this.left = (left===undefined ? null : left)
* this.right = (right===undefined ? null : right)
* }
*/
/**
* @param {TreeNode} root
* @return {TreeNode}
*/
var invertTree = function(root) {
if (root === null) {
return null;
}
// Swap the left and right children
const temp = root.left;
root.left = root.right;
root.right = temp;
// Recursively invert the left and right subtrees
invertTree(root.left);
invertTree(root.right);
return root;
};

49.44MB, 54ms


225. Implement Stack using Queues

225. Implement Stack using Queues

使用兩個隊列實現一個後進先出(LIFO)的堆疊。實現的堆疊應該支持所有正常堆疊的功能(推入、取頂、彈出和判空)。

實現 MyStack 類:

  • void push(int x):將元素 x 推入堆疊的頂部。
  • int pop():移除堆疊頂部的元素並返回該元素。
  • int top():返回堆疊頂部的元素。
  • boolean empty():如果堆疊為空,返回 true;否則返回 false。

注意:

  • 你只能使用隊列的標準操作,這意味著只能使用「後端推入」、「前端查看/彈出」、「查詢大小」和「判空」操作。

  • 根據你使用的語言,隊列可能不原生支持。你可以使用列表或雙端隊列(deque)來模擬隊列,只要你只使用隊列的標準操作即可。

範例:

輸入
["MyStack", "push", "push", "top", "pop", "empty"]
[[], [1], [2], [], [], []]

輸出
[null, null, null, 2, 2, false]



Python


from collections import deque

class MyStack:
def __init__(self):
self.q1 = deque()
self.q2 = deque()

def push(self, x: int) -> None:
self.q2.append(x)
while self.q1:
self.q2.append(self.q1.popleft())
self.q1, self.q2 = self.q2, self.q1

def pop(self) -> int:
return self.q1.popleft()

def top(self) -> int:
return self.q1[0]

def empty(self) -> bool:
return len(self.q1) == 0

16.49MB, 36ms


C++


#include <queue>

class MyStack {
private:
std::queue<int> q1, q2;

public:
MyStack() {}
void push(int x) {
q2.push(x);
while (!q1.empty()) {
q2.push(q1.front());
q1.pop();
}
std::swap(q1, q2);
}
int pop() {
int top = q1.front();
q1.pop();
return top;
}
int top() {
return q1.front();
}
bool empty() {
return q1.empty();
}
};

8.52MB, 0ms


Javascript


class MyStack {
constructor() {
this.q1 = [];
this.q2 = [];
}

push(x) {
this.q2.push(x);
while (this.q1.length > 0) {
this.q2.push(this.q1.shift());
}
[this.q1, this.q2] = [this.q2, this.q1];
}

pop() {
return this.q1.shift();
}

top() {
return this.q1[0];
}

empty() {
return this.q1.length === 0;
}
}

49.05MB, 49ms


224. Basic Calculator

224. Basic Calculator


給定一個表示有效表達式的字串 s,實現一個基本的計算器來計算並返回該表達式的結果。

注意:你不允許使用任何內建函數來將字串作為數學表達式進行計算,例如 eval()。

範例 1:

輸入: s = "1 + 1" 輸出: 2


Python


class Solution:
    def calculate(self, s: str) -> int:
        def calc(it):
            stack = []
            num = 0
            op = '+'
           
            while it < len(s):
                if s[it].isdigit():
                    num = num * 10 + int(s[it])
                elif s[it] in '+-*/':
                    if op == '+':
                        stack.append(num)
                    elif op == '-':
                        stack.append(-num)
                    elif op == '*':
                        stack.append(stack.pop() * num)
                    elif op == '/':
                        stack.append(int(stack.pop() / num))
                    num = 0
                    op = s[it]
                elif s[it] == '(':
                    num, it = calc(it + 1)
                elif s[it] == ')':
                    break
                it += 1
           
            if op == '+':
                stack.append(num)
            elif op == '-':
                stack.append(-num)
            elif op == '*':
                stack.append(stack.pop() * num)
            elif op == '/':
                stack.append(int(stack.pop() / num))
           
            return sum(stack), it
       
        return calc(0)[0]

18.26MB, 18ms


C++


#include <string>
#include <stack>
#include <cctype>

class Solution {
public:
    int calculate(string s) {
        return calc(s, 0).first;
    }

private:
    std::pair<int, int> calc(const string& s, int i) {
        std::stack<int> stack;
        int num = 0;
        char op = '+';

        while (i < s.length()) {
            if (std::isdigit(s[i])) {
                num = num * 10 + (s[i] - '0');
            } else if (s[i] == '(') {
                auto [res, next_i] = calc(s, i + 1);
                num = res;
                i = next_i;
            } else if (s[i] == ')') {
                updateStack(stack, op, num);
                return {getResult(stack), i};
            } else if (s[i] == '+' || s[i] == '-' || s[i] == '*' || s[i] == '/') {
                updateStack(stack, op, num);
                op = s[i];
                num = 0;
            }
            i++;
        }

        updateStack(stack, op, num);
        return {getResult(stack), i};
    }

    void updateStack(std::stack<int>& stack, char op, int num) {
        if (op == '+') stack.push(num);
        else if (op == '-') stack.push(-num);
        else if (op == '*') {
            int top = stack.top();
            stack.pop();
            stack.push(top * num);
        } else if (op == '/') {
            int top = stack.top();
            stack.pop();
            stack.push(top / num);
        }
    }

    int getResult(std::stack<int>& stack) {
        int result = 0;
        while (!stack.empty()) {
            result += stack.top();
            stack.pop();
        }
        return result;
    }
};

15.19MB, 16ms


Javascript


/**
 * @param {string} s
 * @return {number}
 */
var calculate = function(s) {
    const stack = [];
    let num = 0;
    let sign = 1;
    let result = 0;
   
    for (let i = 0; i < s.length; i++) {
        const char = s[i];
       
        if (char >= '0' && char <= '9') {
            num = num * 10 + (char - '0');
        } else if (char === '+' || char === '-') {
            result += sign * num;
            num = 0;
            sign = char === '+' ? 1 : -1;
        } else if (char === '(') {
            stack.push(result);
            stack.push(sign);
            result = 0;
            sign = 1;
        } else if (char === ')') {
            result += sign * num;
            result *= stack.pop(); // Get the sign before the parenthesis
            result += stack.pop(); // Add the result before the parenthesis
            num = 0;
        }
    }
   
    if (num !== 0) result += sign * num;
    return result;
};

54.34MB, 56ms


223. Rectangle Area

223. Rectangle Area



給定在二維平面上兩個直角矩形的座標,返回這兩個矩形覆蓋的總面積。

第一個矩形由其左下角 (ax1, ay1) 和右上角 (ax2, ay2) 定義。

第二個矩形由其左下角 (bx1, by1) 和右上角 (bx2, by2) 定義。


範例


Python


class Solution:
    def computeArea(self, ax1: int, ay1: int, ax2: int, ay2: int, bx1: int, by1: int, bx2: int, by2: int) -> int:
        # Calculate areas of both rectangles
        area1 = (ax2 - ax1) * (ay2 - ay1)
        area2 = (bx2 - bx1) * (by2 - by1)
       
        # Find the overlapping region
        left = max(ax1, bx1)
        right = min(ax2, bx2)
        top = min(ay2, by2)
        bottom = max(ay1, by1)
       
        # Calculate overlapping area
        overlap_area = 0
        if left < right and bottom < top:
            overlap_area = (right - left) * (top - bottom)
       
        # Total area is sum of both areas minus the overlap
        total_area = area1 + area2 - overlap_area
       
        return total_area

16.62MB, 12ms


C++


class Solution {
public:
    int computeArea(int ax1, int ay1, int ax2, int ay2, int bx1, int by1, int bx2, int by2) {
        // Calculate areas of both rectangles
        long long area1 = static_cast<long long>(ax2 - ax1) * (ay2 - ay1);
        long long area2 = static_cast<long long>(bx2 - bx1) * (by2 - by1);
       
        // Find the overlapping region
        int left = max(ax1, bx1);
        int right = min(ax2, bx2);
        int top = min(ay2, by2);
        int bottom = max(ay1, by1);
       
        // Calculate overlapping area
        long long overlap_area = 0;
        if (left < right && bottom < top) {
            overlap_area = static_cast<long long>(right - left) * (top - bottom);
        }
       
        // Total area is sum of both areas minus the overlap
        long long total_area = area1 + area2 - overlap_area;
       
        return static_cast<int>(total_area);
    }
};

9.92MB, 0ms


Javascript


/**
 * @param {number} ax1
 * @param {number} ay1
 * @param {number} ax2
 * @param {number} ay2
 * @param {number} bx1
 * @param {number} by1
 * @param {number} bx2
 * @param {number} by2
 * @return {number}
 */
var computeArea = function(ax1, ay1, ax2, ay2, bx1, by1, bx2, by2) {
    // Calculate areas of both rectangles
    const area1 = (ax2 - ax1) * (ay2 - ay1);
    const area2 = (bx2 - bx1) * (by2 - by1);
   
    // Find the overlapping region
    const left = Math.max(ax1, bx1);
    const right = Math.min(ax2, bx2);
    const top = Math.min(ay2, by2);
    const bottom = Math.max(ay1, by1);
   
    // Calculate overlapping area
    let overlapArea = 0;
    if (left < right && bottom < top) {
        overlapArea = (right - left) * (top - bottom);
    }
   
    // Total area is sum of both areas minus the overlap
    const totalArea = area1 + area2 - overlapArea;
   
    return totalArea;
};

55.62MB, 119ms


2024年8月26日 星期一

碼農新生:Johns Hopkins電腦科學碩士的第一堂課

作者:王廷瑋


第一幕:起跑線上的領跑者


剛踏入Johns Hopkins電腦科學碩士課程的第一天,我就如同參加百米賽跑般,在起跑線上就已經領先一步。憑藉著與舊識快速組隊的優勢,我們團隊宛如一支訓練有素的接力隊,每次作業和專題都以迅雷不及掩耳之勢完成。這種領先優勢就像是滾雪球效應,越滾越大,推動著我們持續保持高水準的輸出。

誰說第一印象不重要?在這裡,它可是決定了至少一半的成敗!


第二幕:在團隊與個人之間尋找平衡


在這場學術馬拉松中,我們就像是在走鋼絲的特技演員,必須在兩個看似矛盾的目標之間保持完美的平衡:

一邊是「群雁齊飛」—— 與同儕協作,互相砥礪,形成一個強大的團隊。我們像是一群遷徙的候鳥,彼此呼應,共同前進。

另一邊則是「獨木成林」—— 培養獨立解決問題的能力,鍛煉自己成為一棵參天大樹。在這個過程中,我們像是孤獨的探險家,在未知的知識叢林中開闢自己的道路。

雖然我們也像考古學家一樣,不斷地在網絡的汪洋大海中尋寶,但面對的卻是全新的未知領域。這種體驗,讓我們如同踏上月球的太空人,為未來探索未知做好了充分準備。

Johns Hopkins的EP課程就像是一間精品店,堅持小班教學,保證每位「顧客」都能得到VIP待遇。我們這些「顧客」被分成幾個小組,既能互相參考,又能在追求卓越的路上齊頭並進。畢竟,長期來看,大家的表現總會回歸平均。所以,一開始就需要像設計師般精心規劃,為自己的作品注入獨特的靈魂。

在這個過程中,我們既要學會在團隊中協作,又要培養獨立思考的能力。這種平衡,就像是在煮一鍋完美的湯 —— 每種ingredientient都要恰到好處,才能激發出最佳的風味。


第三幕:多元共生的團隊生態系


我們的團隊簡直就是一個微型聯合國!兩個白人、兩個華人;兩個電腦科學本科生、兩個生物醫學背景的「異類」。這種多元組合不僅能互補,更能激發出意想不到的火花。電腦科學本科生就像是專業的建築師,精通程式架構與項目管理;而我則是一名出色的室內設計師,擅長報告呈現、抽象思考與文件整理。

白人隊友彷彿天生的社交達人,表達能力一流;華人則是細節控,計劃執行起來一絲不苟。在這個團隊裡,我們就像在參加一場跨文化交流會,每天都在互相學習,共同成長。


第四幕:軟件工程的真相大白


誰說軟件工程就是整天對著電腦敲代碼?那只是冰山一角!在AI大神的加持下,老師甚至豪言:「任何項目的代碼部分,2-3天就能搞定!」

軟件工程的精髓,其實是一場精心策劃的舞台劇。從編劇(項目策劃)、選角(團隊組建)、劇本(需求分析)到舞台設計(系統架構),每一個環節都不容忽視。而寫代碼,不過是演員上台表演的一小部分罷了。最後,還有品質把關、彩排(測試)和長期演出(維護)等諸多工作。

這台大戲中的每一個細節都環環相扣,一旦早期出現任何紕漏,後期都可能釀成無法挽回的災難。所以,軟件工程師其實是集編劇、導演、演員於一身的全能藝術家!


尾聲:AI,我的得力助手


每次完成作業,我們都要寫下學習心得和AI應用體驗。目前看來,AI就像是一個永不疲倦的超級助理,能夠迅速完成各種任務。但它並非萬能,有時輸出的結果並不盡如人意,需要我們不斷溝通和校正。面對複雜問題時,人類的智慧仍然是不可或缺的。





電腦瑣談(Trivial Compute)

作者:王廷瑋




軟體工程


電腦瑣談(Trivial Compute)是一個創新的教育遊戲專案,旨在通過互動式問答遊戲來增進學生對計算機科學概念的理解。這個專案不僅展示了遊戲化學習的潛力,還體現了軟體工程(Software Engineering)的核心原則和最佳實踐。

在開發過程中,團隊製作了多份重要文件,每份文件都在軟體工程中扮演關鍵角色:
 
  • 團隊章程(Team Charter):定義了團隊成員的角色、責任和溝通流程,為專案奠定了堅實的基礎。
  • 專案計畫(Project Plan):概述了專案的生命週期(Life Cycle)、風險評估(Risk Assessment)和資源分配(Resource Allocation),指導整個開發過程。
  • 願景文件(Vision Document):闡明了專案的目標、範圍和價值主張,確保所有相關者(Stakeholders)對產品有共同的理解。
  • 軟體需求規格說明書(Software Requirements Specification, SRS):詳細描述了系統的功能需求(Functional Requirements)和非功能需求(Non-Functional Requirements),為後續設計和開發提供了明確的指導。
  • 設計文件(Design Document):包含了系統的靜態設計(Static Design)和動態設計(Dynamic Design),為開發人員提供了清晰的藍圖。

里程碑


專案採用了分階段交付模型(Staged Delivery Model),包括三個關鍵里程碑(Milestones):
 
Skeletal(骨架)里程碑:
 
  • 建立了基本的系統架構(System Architecture),包括Express伺服器、Firebase數據庫和身份驗證。
  • 實現了REST API端點和客戶端介面(Client Interface)的基本框架。
  • 使用Docker進行容器化(Containerization),確保了跨環境的一致性。

Minimal(最小)里程碑:
 
  • 開發了核心遊戲功能,如遊戲板GUI(Graphical User Interface)、玩家移動邏輯和計分系統。
  • 實現了基本的用戶介面,使遊戲可以進行基本操作。
  • 建立了後端(Backend)、前端(Frontend)和數據庫(Database)之間的基本通信。

Target(目標)里程碑:
 
  • 實現了完整的用戶認證(User Authentication)系統。
  • 添加了動態內容管理(Dynamic Content Management)功能,允許創建和刪除問答卡。
  • 優化了用戶介面和遊戲邏輯(Game Logic)。
  • 實現了安全部署(Secure Deployment)和性能優化(Performance Optimization)。

通過這個專案,團隊不僅創造了一個有趣且有教育價值的遊戲,還實踐了軟體工程的關鍵概念,如需求分析(Requirements Analysis)、系統設計(System Design)、風險管理(Risk Management)和迭代開發(Iterative Development)。"


生成式AI應用


在開發過程中,團隊巧妙地運用了生成式AI技術來輔助各個階段的工作。ChatGPT等大型語言模型(LLMs)被用於協助文件撰寫和優化,特別是在產生初步的需求描述和設計說明時。這些AI工具幫助團隊快速生成初稿,提高了文檔製作的效率。Cursor等AI增強的開發環境提高了編碼效率和代碼質量,為開發人員提供了智能代碼補全和錯誤檢測等功能。

特別值得一提的是Claude,這個AI助手在整個專案中發揮了重要作用。團隊利用Claude來生成創意想法、提供解決方案建議,並協助整理和綜合專案想法。在面對設計挑戰或功能規劃時,Claude的輸出常常為團隊提供了新的思路和靈感。

然而,團隊始終保持警惕,認識到AI只是輔助工具,無法獨自解決複雜的問題。所有AI生成的內容和建議,無論是來自ChatGPT、Cursor還是Claude,都經過了團隊成員的仔細審查和批判性思考。團隊成員運用他們的專業知識和經驗,對AI的輸出進行評估、修改和完善,確保最終的決策和成果符合專案的高標準和具體需求。

這種人機協作的方式不僅提高了開發效率,還為團隊提供了新的視角和創意靈感。同時,這個過程也凸顯了人類專業知識、經驗和判斷力在軟體開發中的不可替代性。"電腦瑣談"專案成功地展示了如何在軟體工程實踐中有效地整合AI工具,同時保持人類專業知識的核心地位,為未來的教育科技開發樹立了新的標準。


Work: 
Email LinkedIn / Github
Research: OCRID / Google Scholar / RearchGate