reoger的记录

--以后的你会感激现在那么努力的自己

0%

PopupWindow 使用实例

popupWindows是一个弹出框的界面载体,类似于AlertDialog,但它比AlertDialog更加灵活,能更加精确的指定其所在的位置。
下面记录一下自定义popupWindows的使用。

自定会CustomPopup,继承自PopupWindow

具体代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81

public class CustomPopup extends PopupWindow {


// PopupWindow中控件点击事件回调接口
private IPopuWindowListener mOnClickListener;
//PopupWindow布局文件中的Button
private Button alarm_pop_btn;

/**
* @param s
* @description 构造方法
* @author ldm
* @time 2016/9/30 9:14
*/
public CustomPopup(Context mContext, int width, int height, IPopuWindowListener listener) {
super(mContext);

this.mOnClickListener = listener;
//获取布局文件
View mContentView = LayoutInflater.from(mContext).inflate(R.layout.popupwindow_layout, null);
//设置布局
setContentView(mContentView);
// 设置弹窗的宽度和高度
// setWidth(width);
// setHeight(height);
setWidth(WindowManager.LayoutParams.MATCH_PARENT);
setHeight(WindowManager.LayoutParams.WRAP_CONTENT);
//设置能否获取到焦点
setFocusable(false);
//设置PopupWindow进入和退出时的动画效果
setAnimationStyle(R.style.MyPopupWindow);
setTouchable(true); // 默认是true,设置为false,所有touch事件无响应,而被PopupWindow覆盖的Activity部分会响应点击
// 设置弹窗外可点击,此时点击PopupWindow外的范围,Popupwindow不会消失
setOutsideTouchable(false);
//外部是否可以点击,设置Drawable原因可以参考:http://blog.csdn.net/harvic880925/article/details/49278705
setBackgroundDrawable(new BitmapDrawable());
// 设置弹窗的布局界面
initUI();
}

/**
* 初始化弹窗列表
*/
private void initUI() {
//获取到按钮
alarm_pop_btn = (Button) getContentView().findViewById(R.id.alarm_pop_btn);
//设置按钮点击事件
alarm_pop_btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (null != mOnClickListener) {
mOnClickListener.dispose();
}
}
});
}

/**
* 显示弹窗列表界面
*/
public void show(View view) {
int[] location = new int[2];
view.getLocationOnScreen(location);
//Gravity.BOTTOM设置在view下方,还可以根据location来设置PopupWindowj显示的位置
int x = location[0];
int y = location[1];
showAtLocation(view, Gravity.BOTTOM, x, y);
}

/**
* @param null
* @author ldm
* @description 点击事件回调处理接口
* @time 2016/7/29 15:30
*/
public interface IPopuWindowListener {
void dispose();
}

}

xml资源文件

布局资源文件:popupwindow_layout.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:background="#ffffff"
android:padding="20dp" >

<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clickable="true"
android:gravity="center"
android:textColor="@android:color/holo_orange_dark"
android:id="@+id/alarm_pop_btn"
android:text="确定" />

<TextView
android:layout_marginTop="20dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:clickable="true"
android:gravity="center"
android:text="取消" />

</LinearLayout>

类型资源文件styles

1
2
3
4
5
<style name="MyPopupWindow">

<item name="android:windowEnterAnimation">@anim/pop_in</item>
<item name="android:windowExitAnimation">@anim/pop_out</item>
</style>

动画资源文件pop_in

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<scale
android:duration="200"
android:fromXScale="0"
android:fromYScale="0"
android:pivotX="50%"
android:pivotY="50%"
android:toXScale="0.8"
android:toYScale="0.5" />
<alpha
android:duration="200"
android:fromAlpha="0.0"
android:toAlpha="1.0" />
</set>

动画资源文件和pop_out

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">

<scale
android:fromXScale="0.8"
android:fromYScale="0.5"
android:pivotX="50%"
android:pivotY="50%"
android:toXScale="0"
android:toYScale="0"
android:duration="200"/>

<alpha
android:duration="200"
android:fromAlpha="1.0"
android:toAlpha="0.0"/>

</set>

在activity中进行调用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

public class MainActivity extends AppCompatActivity implements CustomPopup.IPopuWindowListener {

private CustomPopup alarmPopup;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}



public void testPopupWindow2(View view){
//初始化PopupWindow这里通过数据200来设置PopupWindow高度
alarmPopup=new CustomPopup(MainActivity.this, ViewGroup.LayoutParams.MATCH_PARENT, 200, this);//这里的this是指当前Activity实现了PopupWindow中IPopuWindowListener接口
//弹出PopupWindow
alarmPopup.show(view);
}

@Override
public void dispose() {
if (alarmPopup.isShowing()) {
alarmPopup.dismiss();//关闭PopupWindow
}
}
}

end

参考链接

48. 旋转图像(Rotate Image)

题目难度: 中等

给定一个 n _× _n 的二维矩阵表示一个图像。

将图像顺时针旋转 90 度。

说明:

你必须在旋转图像,这意味着你需要直接修改输入的二维矩阵。请不要使用另一个矩阵来旋转图像。

示例 1:

1
2
3
4
5
6
7
8
9
10
11
12
13
给定 **matrix** = 
[
[1,2,3],
[4,5,6],
[7,8,9]
],

**原地**旋转输入矩阵,使其变为:
[
[7,4,1],
[8,5,2],
[9,6,3]
]

示例 2:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
给定 **matrix** =
[
[ 5, 1, 9,11],
[ 2, 4, 8,10],
[13, 3, 6, 7],
[15,14,12,16]
],

**原地**旋转输入矩阵,使其变为:
[
[15,13, 2, 5],
[14, 3, 4, 1],
[12, 6, 8, 9],
[16, 7,10,11]
]

Solution

思路一

先上线交换,再斜角交换。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
例如,原数组
[
[1,2,3],
[4,5,6],
[7,8,9]
],

上下替换后:
[
[7,8,9],
[4,5,6],
[1,2,3]
],
然后再斜角替换:
[
[7,4,1],
[8,5,2],
[9,6,3]
],

实现代码。
Language: Java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Solution {
   public void rotate(int[][] matrix) {
        int len = matrix.length;
       //上下反转
       for(int i=0;i<len/2;i++){
           for(int j=0;j<len;j++){
              int temp = matrix[i][j];
               matrix[i][j] = matrix[len-i-1][j];
               matrix[len-i-1][j] = temp;
               
          }
      }
       
       //斜角反转
       for(int i=0;i<len;i++){
           for(int j=i+1;j<len;j++){
               int temp = matrix[i][j];
                matrix[i][j] =  matrix[j][i];
               matrix[j][i] =  temp;
          }
      }
  }
}

思路二:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class Solution {
public void rotate(int[][] matrix) {
int N = matrix.length;
int M, row, col, nextRow, nextCol, now, next, offset;
for (int i = 0; i < N / 2; i++) { //圈数
M = (i + 1) * 2 + (N & 1);
for (int j = 0; j < M - 1; j++) { //该圈的长度
offset = N / 2 - i - 1;
row = 0;
col = j;
now = matrix[+offset][col + offset];
for (int k = 0; k < 4; k++) { //换4个
nextRow = col;
nextCol = M - 1 - row;
next = matrix[nextRow + offset][nextCol + offset];
matrix[nextRow + offset][nextCol + offset] = now;
now = next;
row = nextRow;
col = nextCol;
}
}
}
}
}

283. 移动零(Move Zeroes)

题目难度: 简单

给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。

示例:

1
2
**输入:** `[0,1,0,3,12]`
**输出:** `[1,3,12,0,0]`

说明:

  1. 必须在原数组上操作,不能拷贝额外的数组。
  2. 尽量减少操作次数。

Solution

解题思路:

暴力解法。

从后往前遍历,当发现有0时,就其移动到最后,这个移动最后并不是仅仅将这个0和最后一个数字对调,而是将这个0之后所有的数字都往前挪一位。此法简单,暴力,时间复杂度较高,但是容易想到。代码如下:
Language: Java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Solution {
   public void moveZeroes(int[] nums) {
       for(int i=nums.length-1;i>=0;i--){
      if(nums[i] == 0){
      move(nums,i);
      }
      }
  }
    private void move(int[] nums,int target){
  for(int i=target;i<nums.length-1;i++){
  nums[i] = nums[i+1];
  }
  nums[nums.length-1] = 0;
  }
}

将0过滤掉

从0开始遍历数组,维护一个指针pos用于表示当前非零数组的位置,维护一个指针i用于表示当前数组遍历的位置。
[0,1,0,3,12]为例,进行说明。
从0开始遍历数组,发现第一个数字为0,此时pos不做任何改变,仍然为0。
第二个数字为1,此时有nums[pos] = nums[i]nums[0] = nums[1],且pos++,即此时pos=1;
到第三个数字又为0,此时又不做任何改变。
到第四个数字的时候,我们即又num[1] = num[3],且pos++ ,即此时pos = 2.
如此我们就通过pos指针将数组中的0过滤掉了,最后我们添加相应的0到数组后面即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Solution {
public void moveZeroes(int[] nums) {
int pos = 0;
for(int i = 0; i < nums.length; i++){
if(nums[i] != 0){
nums[pos]= nums[i];
pos++;
}
}
for(;pos<nums.length; pos++){
nums[pos] = 0;
}
}
}

66. 加一(Plus One)

题目难度: 简单

给定一个非负整数组成的非空数组,在该数的基础上加一,返回一个新的数组。

最高位数字存放在数组的首位, 数组中每个元素只存储一个数字。

你可以假设除了整数 0 之外,这个整数不会以零开头。

示例 1:

1
2
3
**输入:** [1,2,3]
**输出:** [1,2,4]
**解释:** 输入数组表示数字 123。

示例 2:

1
2
3
**输入:** [4,3,2,1]
**输出:** [4,3,2,2]
**解释:** 输入数组表示数字 4321。

Solution

解题思路

就是大数相加的思想,将数组倒叙,加1大于9就进一位,最后的进位标志为1时,说明需要扩充数组。实现如下
Language: Java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class Solution {
   public int[] plusOne(int[] digits) {
         int len = digits.length;
       List<Integer> list = new ArrayList<Integer>();
       int temp =1;
       for(int i=len-1;i>=0;i--){
           int md = digits[i]+temp;
           if(md>9){
               temp =1;
               list.add(0,md-10);
          }else{
               temp = 0;
               list.add(0,md);
          }
      }
       if(temp ==1 ){
      list.add(0,1);
           len ++;
      }
       int res[] = new int[len];
       for(int i=0;i<list.size();i++){
      res[i] = list.get(i);
      }
       return res;
  }
}

350. 两个数组的交集 II(Intersection of Two Arrays II)

题目难度: 简单

给定两个数组,写一个方法来计算它们的交集。

例如:
给定nums1 = [1, 2, 2, 1], nums2 = [2, 2], 返回 [2, 2].

注意:

  • 输出结果中每个元素出现的次数,应与元素在两个数组中出现的次数一致。
  • 我们可以不考虑输出结果的顺序。

跟进:

  • 如果给定的数组已经排好序呢?你将如何优化你的算法?
  • 如果 _nums1 _的大小比 _nums2 _小很多,哪种方法更优?
  • 如果_nums2_的元素存储在磁盘上,内存是有限的,你不能一次加载所有的元素到内存中,你该怎么办?

Solution

解题思路:
先将两个数组排好序,我们需要维护两个指针,指针i用于指向nums1,指针j指向nums2。当nums1[i] > nums2[j]时,j++,当nums1[i] < nums2[j],i++。我们需要寻找的情况就是有多少对nums1[i] == nums2[j]的情况,记录下来即可,记得把指针i和j往前移一位。

Language: Java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class Solution {
   public int[] intersect(int[] nums1, int[] nums2) {
     if(nums1.length ==0 || nums2.length == 0)
return new int[0];
       Arrays.sort(nums1);
       Arrays.sort(nums2);
       int i=0,j=0;
       List res = new ArrayList<Integer>();
       while(i<nums1.length && j<nums2.length){
           if(nums1[i]==nums2[j]){
               res.add(nums1[i]);
               i++;
               j++;
          }else if(nums1[i]>nums2[j]){
          j++;
          }else if(nums1[i]<nums2[j]){
          i++;
          }
      }
       int a[] = new int[res.size()];
       for(int k=0;k<res.size();k++){
           a[k] = (int) res.get(k);
      }
       return a;
  }
}

只出现一次的数字

给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。
给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。

说明:

你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?

示例 1:

输入: [2,2,1]
输出: 1

示例 2:

输入: [4,1,2,1,2]
输出: 4

常规解法

先排序,排完序在前后两个数字间进行比较,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
class Solution {
public int singleNumber(int[] nums) {
Arrays.sort(nums);
for(int i=0;i<nums.length-1;i++){
if(nums[i]!=nums[i+1]){
return nums[i];
}
i++;
}
return nums[nums.length-1];
}
}

高级解法

利用^,异或,相同为1,不同为0。利用临时变量一直异或,最终得到的一定是与众不同的的那个。

1
2
3
4
5
6
7
8
9
class Solution {
public int singleNumber(int[] nums) {
int k=0;
for(int i =0 ;i<nums.length;i++){
k^=nums[i];
}
return k;
}
}

android中Support Annotation Lobrary 注解

官方文档写的太好了,我觉得不可能有他写的更好的文章了,所以就不打算了写了,官方连接https://developer.android.com/studio/write/annotations?hl=zh-cn

速查表

注解 类型
Nullable 标记的函数可以返回null,或者标记的参数可以为null
NonNull 标记的函数可以不能为空,或者标记的参数不能为空
AnimatorRes 标记整型值是android.R.animator类型
AnimRes 标记整型值是android.R.anim类型
AnyRes 标记整型值是任意资源类型
ArrayRes 标记整型值是android.R.array类型
AttrRes 标记整型值是android.R.attr类型
BoolRes 标记整型值是布尔值类型
ColorRes 标记整型值是android.R.color类型
DrawableRes 标记整型值是android.R.drawable类型
FractionRes 标记整型值是fraction类型
IdRes 标记整型值是android.R.id类型
IntegerRes 标记整型值是android.R.integer类型
InterpolatorRes 标记整型值是android.R.integer类型
LayoutRes 标记整型值是android.R.layout类型
MenuRes 标记整型值是android.R.menu类型
PluralsRes 标记整型值是android.R.plurals类型
RawRes 标记整型值是android.R.raw类型
StringRes 标记整型值是android.R.string类型
StyleableRes 标记整型值是android.R.styleable类型
StyleRes 标记整型值是android.R.style类型
TransitionRes 标记整型值是android.R.transition类型
XmlRes 标记整型值是android.R.xml类型
ColorRes 标记参数类型需要传入的是颜色类型的资源ID
Size 标记参数的大小
Size(min = 1) 标记集合不可以为空
Size(max = 1024) 标记字符串最大的字符个数是1024
Size(2) 表示数组元素个数是2个
Size(multiple = 2) 标记数组的大小是2的倍数
IntRange(from =0,to = 255) 标记参数是从0-255之间的整型
FloatRange(from =0.0,to = 255.0) 标记参数是从0-255之间的浮点型
CallSuper 标记该方法在重写的同时一定要调用被这个方法

参考链接

买卖股票的最佳时机 II

原题链接:https://leetcode-cn.com/explore/interview/card/top-interview-questions-easy/1/array/22/.

给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。

设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易(多次买卖一支股票)。

注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。

示例 1:

输入: [7,1,5,3,6,4]
输出: 7
解释: 在第 2 天(股票价格 = 1)的时候买入,在第 3 天(股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。
随后,在第 4 天(股票价格 = 3)的时候买入,在第 5 天(股票价格 = 6)的时候卖出, 这笔交易所能获得利润 = 6-3 = 3 。

示例 2:

输入: [1,2,3,4,5]
输出: 4
解释: 在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。
注意你不能在第 1 天和第 2 天接连购买股票,之后再将它们卖出。
因为这样属于同时参与了多笔交易,你必须在再次购买前出售掉之前的股票。

示例 3:

输入: [7,6,4,3,1]
输出: 0
解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。

解题思路:
尽可能多的买股票,尽可能买一次股票多挣钱,这是本题的关键。本题最暴力的方法就是利用两层循环,第一层循环从i=0开始,表示应该从哪下手,第二层循环从i+1下手,表示该股票什么时候卖出去。股票卖出去的条件也很简单,首先是确保卖出去比买入的价钱高,并且第二天的价格不会比现在高就可以卖出去了。代码如下。

代码实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Solution {
public int maxProfit(int[] prices) {
int max = 0;
for(int i=0;i<prices.length;i++){
for(int j=i+1;j<prices.length;j++){
if(prices[j] > prices[i] ){
if (j+1==prices.length || prices[j + 1] < prices[j]){
max += prices[j]-prices[i];
i = j+1;
}
}else{
i=j;
}
}
}
return max;
}

}

ViewGroup.LayoutParams 的使用记录

LayoutParams类 一般用来child view(子视图) 向 parent view(父视图)传达自己的意图(孩子想变成什么样向其父亲说明),即子布局想在父布局中显示的属性(例如子布局多大、在那个位置)通过LayoutParams来进行展示。

常见的属性

宽(width)和高(hegit)

宽和高一般来说有三种值:

  1. 确定的数字
  2. MATH_PARENT,和父布局一样大
  3. WRAP_CONTENT,自己本身多大就显示多大

margin

margin属性,上下左右边距。

更多的属性设置,可以参考https://developer.android.com/reference/android/R.styleable#ViewGroup_Layout.

具体使用

例如向一个RelativeLayout的父布局中添加一个View,示例代码如下:

1
2
3
4
RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) view.getLayoutParams();
layoutParams.topMargin = y;
layoutParams.leftMargin = x;
view.setLayoutParams(layoutParams);

注意,父布局xml中是是RelativeLayout,子布局在setLayoutParams时,也必须是RelativeLayout.LayoutParams,否则会报错。

具体实践

添加用户引导,高亮某个按钮时的实现思路。一种总体思路,创建一个透明主题的activity,在activity中按钮的位置,添加一个相同的高亮按钮到这个透明主题的activity中,然后启动这个activity,将其覆盖展现在需要用户引导的界面,如此就实现了用户引导。
重点分析: 在父布局中添加子布局,并指定了位置。
关键代码:

1
2
3
4
5
6
7
8
9
10
//获取指定 view的位置,这个sTargetButton就是目标view
int[] location = new int[2];
sTargetButton.getLocationOnScreen(location);

//将view添加到父布局中,调整到制定位置。
ViewGroup.MarginLayoutParams margin = new ViewGroup.MarginLayoutParams(view.getLayoutParams());
RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) view.getLayoutParams();
layoutParams.topMargin = y;
layoutParams.leftMargin = x;
view.setLayoutParams(layoutParams);

参考

1. 两数之和(Two Sum)

题目难度: 简单

给定一个整数数组和一个目标值,找出数组中和为目标值的两个数。

你可以假设每个输入只对应一种答案,且同样的元素不能被重复利用。

示例:

1
2
3
4
给定 nums = [2, 7, 11, 15], target = 9

因为 nums[**0**] + nums[**1**] = 2 + 7 = 9
所以返回 [**0, 1**]

Solution

Language: Java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Solution {
   public int[] twoSum(int[] nums, int target) {
       if(nums == null || nums.length ==0)
           return null;
       int res[] = new int[2];
       for(int i=0;i<nums.length;i++){
           for(int j=1;j<nums.length;j++){
               if(i!=j && nums[i]+nums[j]== target){
                   res[0] = i;
                   res[1] = j;
                   return res;
              }
          }
      }
       return res;
  }
}

思路二:两遍哈希表

为了对运行时间复杂度进行优化,我们需要一种更有效的方法来检查数组中是否存在目标元素。如果存在,我们需要找出它的索引。保持数组中的每个元素与其索引相互对应的最好方法是什么?哈希表。

通过以空间换取速度的方式,我们可以将查找时间从 O(n)O(n) 降低到 O(1)O(1)。哈希表正是为此目的而构建的,它支持以 近似 恒定的时间进行快速查找。我用“近似”来描述,是因为一旦出现冲突,查找用时可能会退化到 O(n)O(n)。但只要你仔细地挑选哈希函数,在哈希表中进行查找的用时应当被摊销为 O(1)O(1)。

一个简单的实现使用了两次迭代。在第一次迭代中,我们将每个元素的值和它的索引添加到表中。然后,在第二次迭代中,我们将检查每个元素所对应的目标元素(target - nums[i]target−nums[i])是否存在于表中。注意,该目标元素不能是 nums[i]nums[i] 本身!

1
2
3
4
5
6
7
8
9
10
11
12
13
public int[] twoSum(int[] nums, int target) {
Map<Integer, Integer> map = new HashMap<>();
for (int i = 0; i < nums.length; i++) {
map.put(nums[i], i);
}
for (int i = 0; i < nums.length; i++) {
int complement = target - nums[i];
if (map.containsKey(complement) && map.get(complement) != i) {
return new int[] { i, map.get(complement) };
}
}
throw new IllegalArgumentException("No two sum solution");
}

复杂度分析:

  1. 时间复杂度:O(n)O(n), 我们把包含有 nn 个元素的列表遍历两次。由于哈希表将查找时间缩短到 O(1)O(1) ,所以时间复杂度为 O(n)O(n)。

  2. 空间复杂度:O(n)O(n), 所需的额外空间取决于哈希表中存储的元素数量,该表中存储了 nn 个元素。

改进为一遍哈希表

事实证明,我们可以一次完成。在进行迭代并将元素插入到表中的同时,我们还会回过头来检查表中是否已经存在当前元素所对应的目标元素。如果它存在,那我们已经找到了对应解,并立即将其返回。

1
2
3
4
5
6
7
8
9
10
11
public int[] twoSum(int[] nums, int target) {
Map<Integer, Integer> map = new HashMap<>();
for (int i = 0; i < nums.length; i++) {
int complement = target - nums[i];
if (map.containsKey(complement)) {
return new int[] { map.get(complement), i };
}
map.put(nums[i], i);
}
throw new IllegalArgumentException("No two sum solution");
}

复杂度分析:
时间复杂度:O(n), 我们只遍历了包含有 n个元素的列表一次。在表中进行的每次查找只花费 O(1)) 的时间。

空间复杂度:O(n), 所需的额外空间取决于哈希表中存储的元素数量,该表最多需要存储 nn 个元素。

来源https://leetcode-cn.com/articles/two-sum/