Press "Enter" to skip to content

Blog Posts

13. 罗马数字转整数

方法一:

  • 创建一个哈希表将罗马字符与对应的数值关联起来。
  • 然后对字符串进行遍历,由于组合只有两种情况,一种是一个字符,一种是两个字符,其中两个字符优先于一个字符
  • 先判断两个字符的组合在哈希表中是否存在,存在则将值取出加到结果ans中,并向后移两个字符。不存在则判断当前1个字符是否存在,存在则将值去除加到结果ans中,并向后移1个字符,最后遍历结束返回结果ans

C 代码题解

int romanToInt(char* s) {
    int symbolValues[26];
    symbolValues['I' - 'A'] = 1;
    symbolValues['V' - 'A'] = 5;
    symbolValues['X' - 'A'] = 10;
    symbolValues['L' - 'A'] = 50;
    symbolValues['C' - 'A'] = 100;
    symbolValues['D' - 'A'] = 500;
    symbolValues['M' - 'A'] = 1000;
    int ans = 0;
    int n = strlen(s);
    for (int i = 0; i < n; ++i) {
        int value = symbolValues[s[i] - 'A'];
        if (i < n - 1 && value < symbolValues[s[i + 1] - 'A']) {
            ans -= value;
        } else {
            ans += value;
        }
    }
    return ans;
}

Python3 代码题解

class Solution:

    SYMBOL_VALUES =  {
        'I': 1,
        'V': 5,
        'X': 10,
        'L': 50,
        'C': 100,
        'D': 500,
        'M': 1000,
    }

    def romanToInt(self, s: str) -> int:
        ans = 0
        n = len(s)
        for i, ch in enumerate(s):
            value = Solution.SYMBOL_VALUES[ch]
            //判断当前字符是否是特殊情况,即当前字符的数值小于下一个字符的数值。如果是特殊情况,需要减去当前字符的数值。
            if i < n - 1 and value < Solution.SYMBOL_VALUES[s[i + 1]]:
                ans -= value
            else:
                ans += value 
        return ans

Source: LeetCode(The title reproduced in this blog is for personal study use only)

The difference between python3 function passing parameters * and **

positional argument
keyword argument

The difference between *args and **kwargs, both are variadic arguments in python:

*args represents any number of unnamed arguments, which is essentially a tuple

**kwargs means keyword arguments, which is essentially a dict

When using both *args and **kwargs, the *args argument must be listed before **kwargs.


Source: Python Crash Course, 2nd Edition A Hands-On:

Note: You’ll often see the generic parameter name *args, which collects arbitrary positional
arguments like this.

Note: You’ll often see the parameter name **kwargs used to collect non-specific keyword
arguments.

9. 回文数

方法一:

反转一半数字:例如输入1331,我们可以将数字“1331”的后半部分从“31”反转成“13”在和前半部分进行比较,如果二者相同我们就得知数字“1331”是回文数

C 代码解法

#include<stdbool.h>

bool isPalindrome(int x){
    // 特殊情况处理:如果 x 是负数或者末尾是 0 的非零数,则不可能是回文数
    if (x < 0 || (x != 0 && x % 10 == 0)){
        return false;
    }

    long reversed_num = 0;
    int original_x = x;

    //反转 x 的一半
    while (x > 0){
        int digit = x % 10;
        reversed_num = reversed_num * 10 + digit;
        x /= 10;
    }

    // 如果原始数字长度是奇数,去掉最后一位
    if (original_x == reversed_num || original_x == reversed_num / 10){
        return true;
    } else {
        return false;
    }
}

Python3 代码解法

class Solution:
    def isPalindrome(self, x: int) -> bool:
        x = str(x)
        if x == x[::-1]:
            return True
        else:
            return False

Source: LeetCode(The title reproduced in this blog is for personal study use only)

Zen of Python

The Zen of Python is a collection of 19 “guiding principles” for writing computer programs that influence the design of the Python programming language. Software engineer Tim Peters wrote this set of principles and posted it on the Python mailing list in 1999. Peters’s list left open a 20th principle “for Guido to fill in”, referring to Guido van Rossum, the original author of the Python language. The vacancy for a 20th principle has not been filled.

Peters’s Zen of Python was included as entry number 20 in the language’s official Python Enhancement Proposals and was released into the public domain. It is also included as an Easter egg in the Python interpreter, where it can be displayed by entering import this.

Principles

The principles are listed as follows:

  • Beautiful is better than ugly.
  • Explicit is better than implicit.
  • Simple is better than complex.
  • Complex is better than complicated.
  • Flat is better than nested.
  • Sparse is better than dense.
  • Readability counts.
  • Special cases aren’t special enough to break the rules.
  • Although practicality beats purity.
  • Errors should never pass silently.
  • Unless explicitly silenced.
  • In the face of ambiguity, refuse the temptation to guess.
  • There should be one– and preferably only one –obvious way to do it.
  • Although that way may not be obvious at first unless you’re Dutch.
  • Now is better than never.
  • Although never is often better than right now.
  • If the implementation is hard to explain, it’s a bad idea.
  • If the implementation is easy to explain, it may be a good idea.
  • Namespaces are one honking great idea – let’s do more of those!

K&R2 solutions: Chapter 3 – Control Flow

Exercise 3.1 Our binary search makes two tests inside the loop, when one would suffice (at the price of more tests outside). Write a version with only one test inside the loop and measure the difference in run-time.

Original for loop code:

/* binsearch: find x in v[0] <= v[1] <= ... <= v[n-1] */
int binsearch(int x, int v[], int n)
{
    int low, high, mid;
    low = 0;
    high = n - 1;
    while (low <= high) {
        mid = (low + high) / 2;
        if (x < v[mid])
            high = mid + 1;
        else if (x > v[mid])
            low = mid + 1;
        else /* found match */
            return mid;
    }
    return -1; /* no match */
}

Modified code:

#include<stdio.h>

int binsearch(int x, int v[], int n);

main() {
    int arr[] = { 1,3,5,7,8,10,22,24,26,28,41,43,45,47,50,51 };
    printf("%d", binsearch(7,arr,10));
}

int binsearch(int x, int v[], int n) {
    int low, high, mid;

    low = 0;
    high = n - 1;

    mid = (low + high) / 2;

    while (low < high && x != v[mid]) {
        if (x > v[mid]){
            low = mid + 1;
        } else {
            high = mid - 1;
        }
        mid = (low + high) / 2;
    }
    if (x == v[mid]){
        return mid;
    } else {
        return -1;
    }
}

Exercise 3.2 Write a function escape(s,t) that converts characters like newline and tab into visible escape sequences like \n and \t as it copies the string t to s . Use a switch . Write a function for the other direction as well, converting escape sequences into the real characters.

K&R2 solutions: Chapter 2 – Types, Operators and Expressions

Exercise 2-1. Write a program to determine the ranges of char , short , int , and long variables, both signed and unsigned , by printing appropriate values from standard headers and by direct computation. Harder if you compute them: determine the ranges of the various floating-point types.

#include<stdio.h>
#include<limits.h>

/* determine ranges of types */
main() {
    /* signed types */
    printf("signed char min = %d\n", SCHAR_MIN);
    printf("signed char max = %d\n", SCHAR_MAX);
    printf("signed short min = %d\n", SHRT_MIN);
    printf("signed short max = %d\n", SHRT_MAX);
    printf("signed int min = %d\n", INT_MIN);
    printf("signed int max = %d\n", INT_MAX);
    printf("signed long min = %d\n", LONG_MIN);
    printf("signed long max = %d\n", LONG_MIN);

    /* unsigned types */
    printf("unsigned char max = %u\n", UCHAR_MAX);
    printf("unsigned short max = %u\n", USHRT_MAX);
    printf("unsigned int max = %u\n", UINT_MAX);
    printf("unsigned long max = %lu\n", ULONG_MAX);
}

Output Result:

signed char min = -128
signed char max = 127
signed short min = -32768
signed short max = 32767
signed int min = -2147483648
signed int max = 2147483647
signed long min = -2147483648
signed long max = -2147483648
unsigned char max = 255
unsigned short max = 65535
unsigned int max = 4294967295
unsigned long max = 4294967295

#include<stdio.h>

/* determine ranges of types */
main() {
    /* signed types */
    printf("signed char min = %d\n",
                    -(char)((unsigned char)~0 >> 1));
    printf("signed char max = %d\n",
                    (char)((unsigned char)~0 >> 1));
    printf("signed short min = %d\n",
                    -(short)((unsigned short)~0 >> 1));
    printf("signed short max = %d\n",
                    (short)((unsigned short)~0 >> 1));
    printf("signed int min = %d\n",
                    -(int)((unsigned int)~0 >> 1));
    printf("signed int max = %d\n",
                    (int)((unsigned int)~0 >> 1));
    printf("signed long min = %d\n",
                    -(long)((unsigned long)~0 >> 1));
    printf("signed long max =  %d\n",
                    (long)((unsigned long)~0 >> 1));

    /* unsigned types */
    printf("unsigned char max = %u\n", 
                    (unsigned char)~0);
    printf("unsigned short max = %u\n",
                    (unsigned short)~0);
    printf("unsigned int max = %u\n",
                    (unsigned int)~0);
    printf("unsigned long max = %u\n",
                    (unsigned long)~0);
}

Output Result:

signed char min = -127
signed char max = 127
signed short min = -32767
signed short max = 32767
signed int min = -2147483647
signed int max = 2147483647
signed long min = -2147483647
signed long max =  2147483647
unsigned char max = 255
unsigned short max = 65535
unsigned int max = 4294967295
unsigned long max = 4294967295

Exercise 2-2. Write a loop equivalent to the for loop above without using && or ||.

Original for loop code:

for(i=0; i<lim-1 && (c=getchar()) != '\n' && c != EOF; ++i)
  s[i] = c;

Modified code:

#include<stdio.h>

/*
  for(i=0; i<lim-1 && (c=getchar()) != '\n' && c != EOF; ++i)
    s[i] = c;
*/

enum loop {NO, YES};
enum loop okloop = YES;
#define MAXLINE 80

main(){
    int c, i = 0, s[MAXLINE];
    int lim = MAXLINE;
    while (okloop == YES){
        if (i >= lim-1){
            okloop = NO;
        } else if ((c = getchar()) != '\n'){
            okloop = NO;
        } else if (c != EOF){
            okloop = NO;
        } else {
            s[i] = c;
            ++i;
        }
    }
}

Exercise 2-3. Write the function htoi(s) , which converts a string of hexadecimal digits (including an optional 0x or 0X) into its equivalent integer value. The allowable digits are 0 through 9, a through f, and A through F .

#include<stdio.h>

#define MAXLINE 100
#define YES 1
#define NO  0

int getline(char line[], int maxline);
int htoi(char s[]);

main(){
    int value;
    char line[MAXLINE];
    getline(line, MAXLINE);
    value = htoi(line);

    printf("The value of %s is %d \n", line, value);
}

int getline(char s[], int lim){
    int c, i;
    for (i = 0; i < lim-1 && ((c = getchar()) != EOF) && c != '\n'; ++i){
        s[i] = c;
    }
    if (c == '\n'){
        s[i] = c;
        ++i;
    }
    s[i] = '\0';
    return i;
}

/* htoi: convert hexadecimal string's to integer*/
int htoi(char s[]){
    int hexdigit, i, inhex, n;

    i = 0;
    if (s[i] == '0'){       /* skip optionel 0x or 0X*/
        ++i;
        if (s[i] == 'x' || s[i] == 'X'){
            ++i;
        }
    }
    n = 0;                  /* integer value to be returned    */
    inhex = YES;            /* assume valid hexedecimal digit  */
    for ( ; inhex == YES; ++i){
        if (s[i] >= '0' && s[i] <= '9'){
            hexdigit = s[i] - '0';
        } else if (s[i] >= 'a' && s[i] <= 'f'){
            hexdigit = s[i] - 'a' + 10;
        } else if (s[i] >= 'A' && s[i] <= 'F'){
            hexdigit = s[i] - 'A' + 10;
        } else {
            inhex = NO;     /* not a valid hexadecimal digit    */
        }
        if (inhex == YES){
            n = 16 * n + hexdigit;
        }
    }
    return n;
}

For example to convert 0XAF.

  1. We strip off 0X.
  2. For A, we get the value hexdigit = 10
  3. n = 16 * 0 + 10 = 10
  4. We gather F, we store hexdigit = ‘F’ – ‘A’ + 10;= 70 – 65 + 10; (70 is ascii value for F, 65 is ascii value for A) = 15
  5. n = 16 n + hexdigit = 16 10 + 15 = 160 + 15 = 175

Exercise 2-4. Write an alternate version of squeeze(s1,s2) that deletes each character in the string s1 that matches any character in the string s2 .

#include<stdio.h>
#define MAXLINE 1000

int mgetline(char line[], int maxline);
void squeeze(char s1[], char s2[]);

main(){
    char s1[MAXLINE], s2[MAXLINE];
    putchar('s');
    putchar('1');
    mgetline(s1, MAXLINE);

    putchar('s');
    putchar('2');
    mgetline(s2, MAXLINE);

    squeeze(s1, s2);

    printf("%s",s1);

    return 0;

}

int mgetline(char s[], int lim){
    int i, c;

    for (i = 0; 1 < lim-1 && (c = getchar()) != EOF && c != '\n'; ++i){
        s[i] = c;
    }
    if (c == '\n'){
        s[i++] = c;
    }
    s[i] = '\0';
}

void squeeze(char s1[],char s2[]){
    int i, j, k;
    k = 0;

    for (i = 0; s1[i] != '\0'; ++i){
        for (j = 0; (s1[i] != s2[j]) && s2[j] != '\0'; ++j)
            ;
        if (s2[j] == '\0'){
            s1[k++] = s1[i];
        }
    }
    s1[k] = '\0';
}

Explanation:

Let’s take the two inputs strings as:

s1: Hello,World

s2: ol

Our desired output is:

He,Wrd

This has removed the characters o and l from the first string. The way squeeze works is, it take each character from the first string and if there is no match found, stores it with a new index k. If there is a match found in s2, it simply skips it. The way it skips is realized by the following:

for(j=0; (s1[i]!=s2[j]) && s2[j]!='\0' ;++j)
    ;
if(s2[j]=='\0')
    s1[k++] = s1[i];

When the match is found s1[i] == s2[j] so our first for loop will end. The second if condtion will fail too as s2 is not iterated till the end, so we do not place the character in s1[k++] and we have successfully skipped it.

Exercise 2-5: Write the function any(s1,s2) , which returns the first location in the string s1 where any character from the string s2 occurs, or -1 if s1 contains no characters from s2 . (The standard library function strpbrk does the same job but returns a pointer to the location.)

#include<stdio.h>
#define MAXLINE 1000

int getline(char line[], int maxline);
int any(char s1[], char s2[]);

main(){
    char s1[MAXLINE], s2[MAXLINE];
    int val;

    getline(s1, MAXLINE);

    getline(s2, MAXLINE);

    val = any(s1, s2);
    printf("%d", val);
    return 0;
}

int getline(char s[], int lim){
    int i, c;
    for (i = 0; i < lim-1 && (c = getchar()) != EOF && c != '\n'; ++i){
        s[i] = c;
    }
    if (c == '\n'){
        s[i++] = c;
    }
    s[i] = '\0';
}

int any(char s1[], char s2[]){
    int i, j;
    for (i = 0; s1[i] != '\0'; ++i){
        // iterate through s2 while trying to find matching character from s1
        for (j = 0; (s1[i] != s2[j]) && s2[j] != '\0'; ++j)
            ;   //continue
        if (s2[j] != '\0' && s2[j] != '\n'){
            return i;
        }

    }
    return -1;
}

ASCII

ASCII(American Standard Code for Information Interchange,美国信息交换标准代码)是基于拉丁字母的一套电脑编码系统。它主要用于显示现代英语,而其扩展版本延伸美国标准信息交换码则可以部分支持其他西欧语言,并等同于国际标准ISO/IEC 646。

美国信息交换标准代码是这套编码系统的传统命名,互联网号码分配局现在更倾向于使用它的新名字US-ASCII。

美国信息交换标准代码是美国电气和电子工程师协会里程碑之一。

ASCII 由电报码发展而来。第一版标准发布于1963年 ,1967年经历了第一次主要修订, 最后一次 更新则是在1986年,至今为止共定义了128个字符;其中33个字符无法显示(一些终端提供了扩展,使得这些字符可显示为诸如笑脸、扑克牌花式得8-bit符号),且这33个字符多数都已是陈废的控制字

符。控制字符的用途主要是用来操控已经处理过的文字。在33个字符之外的是95个可显示的字符。用键盘敲下空白建所产生的空白字符也算1个可显示字符(显示为空白)。

1968年版ASCII编码速见表

控制字符

ASCII控制字符的编号范围是0-3和127(0x00-0x1F和0x7F),共33个字符。

为方便人类用户阅读,各个控制字符均匀有Unicode表示法和脱出字符表示法:

  • Unicode表示法:当想在画面或纸上表示这些控制字符时,就会显示成这个样子。过于老旧的系统或浏览器可能会看不到。使用微软任一中文输入法,输入U2400即可看到␀,输入U2401可看到␁,依此类推。
  • 脱出字符表示法:通常用于终端连线(例如Telnet通信协议),以脱出字符^开头,再接一个符号,用来让这些控制字符得以在画面上显现。虽然看起来是两个字符,但在终端上实际只有一个字符。在绝大部分的终端系统中,包括Windows的命令提示字符(cmd.exe)、Linux和FreeBSD,都可用Ctrl代表脱出字符,输入想要的ASCII控制字符。例如想输入空字符,就要输入Ctrl+2,而非^@,后者会显示成两字符,前者只会显示成一字符。

ASCII控制字符(共33个)

二进制十进制十六进制缩写Unicode
表示法
脱出字符
表示法
名称/意义
0000 0000000NUL^@空字符(Null)
0000 0001101SOH^A标题开始
0000 0010202STX^B本文开始
0000 0011303ETX^C本文结束
0000 0100404EOT^D传输结束
0000 0101505ENQ^E请求
0000 0110606ACK^F确认回应
0000 0111707BEL^G响铃
0000 1000808BS^H退格
0000 1001909HT^I水平定位符号
0000 1010100ALF^J换行键
0000 1011110BVT^K垂直定位符号
0000 1100120CFF^L换页键
0000 1101130DCR^MCR (字符)
0000 1110140ESO^N取消变换(Shift out)
0000 1111150FSI^O启用变换(Shift in)
0001 00001610DLE^P跳出数据通讯
0001 00011711DC1^Q设备控制一(XON 激活软件速度控制)
0001 00101812DC2^R设备控制二
0001 00111913DC3^S设备控制三(XOFF 停用软件速度控制)
0001 01002014DC4^T设备控制四
0001 01012115NAK^U确认失败回应
0001 01102216SYN^V同步用暂停
0001 01112317ETB^W区块传输结束
0001 10002418CAN^X取消
0001 10012519EM^Y连线介质中断
0001 1010261ASUB^Z替换
0001 1011271BESC^[退出键
0001 1100281CFS^\文件分割符
0001 1101291DGS^]组群分隔符
0001 1110301ERS^^记录分隔符
0001 1111311FUS^_单元分隔符
 
0111 11111277FDEL^?Delete字符

可显示字符

可显示字符编号范围是32-126(0x20-0x7E),共95个字符。

ASCII可显示字符(共95个)

Full ASCII Table:

二进制十进制十六进制图形
0010 00003220(space)
0010 00013321!
0010 00103422
0010 00113523#
0010 01003624$
0010 01013725%
0010 01103826&
0010 01113927
0010 10004028(
0010 10014129)
0010 1010422A*
0010 1011432B+
0010 1100442C,
0010 1101452D
0010 1110462E.
0010 1111472F/
0011 000048300
0011 000149311
0011 001050322
0011 001151333
0011 010052344
0011 010153355
0011 011054366
0011 011155377
0011 100056388
0011 100157399
0011 1010583A:
0011 1011593B;
0011 1100603C<
0011 1101613D=
0011 1110623E>
0011 1111633F?
0100 00006440@
0100 00016541A
0100 00106642B
0100 00116743C
0100 01006844D
0100 01016945E
0100 01107046F
0100 01117147G
0100 10007248H
0100 10017349I
0100 1010744AJ
0100 1011754BK
0100 1100764CL
0100 1101774DM
0100 1110784EN
0100 1111794FO
0101 00008050P
0101 00018151Q
0101 00108252R
0101 00118353S
0101 01008454T
0101 01018555U
0101 01108656V
0101 01118757W
0101 10008858X
0101 10018959Y
0101 1010905AZ
0101 1011915B[
0101 1100925C\
0101 1101935D]
0101 1110945E^
0101 1111955F_
0110 00009660`
0110 00019761a
0110 00109862b
0110 00119963c
0110 010010064d
0110 010110165e
0110 011010266f
0110 011110367g
0110 100010468h
0110 100110569i
0110 10101066Aj
0110 10111076Bk
0110 11001086Cl
0110 11011096Dm
0110 11101106En
0110 11111116Fo
0111 000011270p
0111 000111371q
0111 001011472r
0111 001111573s
0111 010011674t
0111 010111775u
0111 011011876v
0111 011111977w
0111 100012078x
0111 100112179y
0111 10101227Az
0111 10111237B{
0111 11001247C|
0111 11011257D}
0111 11101267E~

电子纸

电子纸,简称ePaper,是显示器技术,重点在于模仿以在纸上印刷、书写的视觉观感,而耗电量极小。不同于一般的有机发光二极管(OLED)以发光达成显示功能,电子纸如同普通纸一样,依靠环境光照亮所以理论上阅读起来比较舒适,而且其显示的影像能在阳光直照下仍然清晰可见,可视角极广理论上为180度,其对比度比其他显示技术高不少,大至而报章印刷效果相同,甚至更好。

电子墨水示意图 电泳显示

微胶囊电泳显示器(Microencapsulated EPD, Microencapsulated ElectroPhoretic Display)是一种运用施加电场重新排列带电色素粒子以显像的技术。

1990 年代, 另一种建构于“微胶囊电泳显示”电子墨水的技术原型在麻省理工学院出的研究所团队被实现出并被称为Nature Paper。J.D. Albert, Barrett Comiskey, Joseph Jacobson, Jeremy Rubin and Russ Wilcox 等人在 1997年将此技术商业化而创立了E Ink公司。 紧接着二年后,E Ink公司和Philips Components创建了伙伴关系以共同研发并发销此项技术。在2005年,Philips将这项电纸事业和相关专利让售给Prime View International公司。

长久以来,研发人员企图创造一种可挠,低价的电纸类显示介质。在这种情境下,微粒子显示技术吸引了 研发人员的长期关注。可切换对比的显示技术 以电气驱动高散射性 或吸收性的微粒子( 0.1-5mm尺度范围内 ),不同于液晶显示的微分子特性 . 微粒子型的显示技术的双稳态本质, 可以 直流电场 达到 非常低的耗电效率 同时拥有高对比和光反射率。这些特性, 结合 near-lambertian 观赏特性,产生 纸上墨迹 的视觉效果。但这种显示技术注定会受限于短生命周期和不易量产的 不良副作用。因此在导入以微胶囊封装了电泳粒子的 电泳墨水技术, 可以解决短生命周期 的缺点,同时又能完全以印刷方式制造双稳态电子显示屏。此系统就能让电纸满足实用的需求。

电泳显示方案

采用彩色滤光片的电泳显示方案 目前限制

相比其他低耗电显示解决方案,如LCD,电子纸的刷新速度极低。导致生产商很难在应用电子纸的移动设备上实现诸如如弹出式菜单、光标操作、窗口滚动等需要较复杂交互式操作的功能,而这些功能已经日常化,并且常见于一般的移动设备上。一个很鲜明的例子就是电子纸无法快速平滑放大缩小文档,必须借助网点技术以加快速度。 另外一个缺点是电子纸容易产生“残影”(前一页面的图像留在下一页面上)。虽然这种图像残留容易让人想起CRT电视和等离子电视的磷质烙印现象,但事实上电子纸上的图像残留是非永久性的,可以靠全黑全白屏幕迅速切换解决这一问题,这也是电子书相关厂商解决翻页残留的方法。

电子墨水技术之示意图

  1. 上层
  2. 透明电极层
  3. 透明微胶囊
  4. 带正电荷的白色颜料
  5. 带负电荷的黑色颜料
  6. 透明液体(油)
  7. 电极像素层
  8. 基板
  9. 光线
  10. 白色
  11. 黑色

1. 两数之和

方法一:暴力枚举

最容易想到的方法是枚举数组中的每一个数x,寻找数组中是否存在 target - x

当我们使用遍历整个数组的方式寻找 target - x 时,需要注意到每一个位于 x

C 代码解法

/**
 * Note: The returned array must be malloced, assume caller calls free().
 */
int* twoSum(int* nums, int numsSize, int target, int* returnSize){
    for (int i = 0; i < numsSize; ++i){
        for(int j = i + 1; j < numsSize; ++j){
            if (nums[i] + nums[j] == target){
                int* ret = malloc(sizeof(int) * 2);
                ret[0] = i;
                ret[1] = j;
                *returnSize = 2;
                return ret;
            }
        }
    }
    *returnSize = 0;
    return NULL;
}

C++ 代码解法

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        int n = nums.size();
        for (int i = 0; i < n; ++i) {
            for (int j = i + 1; j < n; ++j) {
                if (nums[i] + nums[j] == target) {
                    return {i, j};
                }
            }
        }
        return {};
    }
};

Python3 代码解法

class Solution:
    def twoSum(self, nums: List[int], target: int) -> List[int]:
        n = len(nums)
        for i in range(n):
            for j in range(i + 1, n):
                if nums[i] + nums[j] == target:
                    return [i,j]
        return []

Java 代码解法

class Solution {
    public int[] twoSum(int[] nums, int target) {
        int n = nums.length;
        for(int i = 0; i < n; ++i){
            for(int j = i + 1; j < n; ++j){
                if(nums[0] + nums[1] == target){
                    return new int[]{i,j};
                }
            }
        }
        return new int[0];
    }
}

复杂度分析 时间复杂度:O(N^2),其中 N 是数组中的元素数量。最坏情况下数组中任意两个数都要被匹配一次。 空间复杂度:O(1)。

方法二:哈希表

注意到方法一的时间复杂度较高的原因是寻找到 target - x 的时间复杂度过高。因此,我们需要一个更优秀的方法,能够快速寻找数组中是否存在目标元素。如果存在,我们需要找出他的索引。

使用哈希表,可以将寻找 target - x 的时间复杂度降低到从 O(N) 降低到 O(1) 。

这样我们创建一个哈希表,对于每一个 x ,我们首先查询哈希表中是否存在 target - x,然后将 x 插入到哈希表中,即可保证不会让 x 和自己匹配。

Python 代码解法

class Solution:
    def twoSum(self, nums: List[int], target: int) -> List[int]:
        hashtable = dict()
        for i, num in enumerate(nums):
            if target - num in hashtable:
                return [hashtable[target - num], i]
            hashtable[nums[i]] = i
        return []

Java 代码解法

class Solution {
    public int[] twoSum(int[] nums, int target) {
        Map<Integer, Integer> hashtable = new HashMap<Integer, Integer>();
        for (int i = 0; i < nums.length; ++i) {
            if (hashtable.containsKey(target - nums[i])) {
                return new int[]{hashtable.get(target - nums[i]), i};
            }
            hashtable.put(nums[i], i);
        }
        return new int[0];
    }   
}

Source: LeetCode(The title reproduced in this blog is for personal study use only)