leetcode刷题记录(137、303、950、125)

2019.1.23 leetcode 刷题总结

题号:137

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

示例 1:
输入: [2,2,3,2]
输出: 3
示例 2:
输入: [0,1,0,1,0,1,99]
输出: 99

我的想法:

  1. 将所给数组排序,索引index从0开始,比较indexindex+1位置上的数是否相同,若相同,index = index + 3,跳到下一组去校验;若不同,返回nums[index];
  2. 上面index的范围在[0,nums.length - 1],若上面没返回,说明在结果在排序后的数组的最后一位,返回nums[nums.length - 1]。

对应程序:

// java
class Solution {
    public int singleNumber(int[] nums) {
    	Arrays.sort(nums);
    	
    	for(int i = 0; i < nums.length - 1; i += 3) {
    		if(nums[i] != nums[i + 1]) {
    			return nums[i];
    		}
    	}
    	
        return nums[nums.length - 1];
    }
}

题号:303

给定一个整数数组 nums,求出数组从索引 i 到 j (i ≤ j) 范围内元素的总和,包含 i, j 两点。

示例:
给定 nums = [-2, 0, 3, -5, 2, -1],求和函数为 sumRange()
sumRange(0, 2) -> 1
sumRange(2, 5) -> -1
sumRange(0, 5) -> -3

说明:
你可以假设数组不可变。
会多次调用 sumRange 方法。

我的想法:

  • 把构造函数中传进来的数组传递给该类的一个变量,在sumRange()方法中相加返回,程序代码就不贴了

优化:

  • 肯定不会是上面这么简单的想法,题目中说明会多次调用sumRange()方法,因此,我们可以在构造函数中,将所有的前i项(i >= 0 && i <= nums.length - 1)的和缓存(这里用数组sum)起来,在调用sumRange()方法时,直接返回sum[j] - sum[i - 1]就可以
程序:
// java
class NumArray {
	private int[] sum;
	
    public NumArray(int[] nums) {
    	sum = new int[nums.length];
    	
    	for(int i = 0; i < sum.length; ++i) {
    		if(i == 0) {
    			sum[i] = nums[i];
    		}else {
    			sum[i] = sum[i - 1] + nums[i];
    		}
    	}
    }
    
    public int sumRange(int i, int j) {
    	if(i == 0) {
    		return sum[j];
    	}else {
    		return sum[j] - sum[i - 1];
    	}
    }
}

题号:950

牌组中的每张卡牌都对应有一个唯一的整数。你可以按你想要的顺序对这套卡片进行排序。
最初,这些卡牌在牌组里是正面朝下的(即,未显示状态)。
现在,重复执行以下步骤,直到显示所有卡牌为止:
从牌组顶部抽一张牌,显示它,然后将其从牌组中移出。
如果牌组中仍有牌,则将下一张处于牌组顶部的牌放在牌组的底部。
如果仍有未显示的牌,那么返回步骤 1。否则,停止行动。
返回能以递增顺序显示卡牌的牌组顺序。
答案中的第一张牌被认为处于牌堆顶部

示例:
输入:[17,13,11,2,3,5,7]
输出:[2,13,3,11,5,17,7]
解释:
我们得到的牌组顺序为 [17,13,11,2,3,5,7](这个顺序不重要),然后将其重新排序。
重新排序后,牌组以 [2,13,3,11,5,17,7] 开始,其中 2 位于牌组的顶部。
我们显示 2,然后将 13 移到底部。牌组现在是 [3,11,5,17,7,13]。
我们显示 3,并将 11 移到底部。牌组现在是 [5,17,7,13,11]。
我们显示 5,然后将 17 移到底部。牌组现在是 [7,13,11,17]。
我们显示 7,并将 13 移到底部。牌组现在是 [11,17,13]。
我们显示 11,然后将 17 移到底部。牌组现在是 [13,17]。
我们展示 13,然后将 17 移到底部。牌组现在是 [17]。
我们显示 17。
由于所有卡片都是按递增顺序排列显示的,所以答案是正确的。

我的想法:

  1. 开始想从结果数组找规律,只发现偶数索引上的数值是从小到大,奇数索引的规律有点乱,放弃。
  2. 看了评论,有一种数据结构是Deque,双向队列,在队列的两端都可以进行入队和出队
  3. 从结果往回推,以本题为例:
    反向推导
  • 图片中左边是正在递增的数组,右边是正在减少的结果数组,从上到下,就是题目中给出的示例的过程,我们要做的就是从下到上,将结果数组还原回去
  • 从下到上观察右侧数组,它的元素是从一个递增的数组的末尾元素添加得到的,当右边数组元素个数小于1时,新增加的元素事直接插入到数组前面的,随着数组中元素个数的增加,在新元素添加到右边数组的头部时,要先将现有数组中的最后一个元素移至头部,再将新元素插入
  • 当然,存在这么多移动元素,插入元素的操作,肯定不要用数组,用的数据结构就是上面提到的Deque

对应程序:

// java
class Solution {
    public int[] deckRevealedIncreasing(int[] deck) {
        // 将原数组排序
    	Arrays.sort(deck);
        // 双端队列Deque
    	Deque<Integer> deque = new LinkedList<>();
    	
    	for(int i = deck.length - 1; i >= 0; --i) {
    		if(deque.size() < 2) {
                // offerFirst:将元素添加在首部
    			deque.offerFirst(deck[i]);
    		}else {
    			// 先将原队列中的最后一个元素放到队列的首部
    			// pollLast:将最后一个元素弹出弹出队列
    			deque.offerFirst(deque.pollLast());
                // 再将新元素插入到队列的首部
    			deque.offerFirst(deck[i]);
    		}
    	}
    	
        int[] res = new int[deck.length];
    	for(int i = 0; i < res.length; ++i) {
    		res[i] = deque.pollFirst();
    	}
    	
    	return res;
    }
}

题号:125

给定一个字符串,验证它是否是回文串,只考虑字母和数字字符,可以忽略字母的大小写。
说明:本题中,我们将空字符串定义为有效的回文串。

示例 1:
输入: “A man, a plan, a canal: Panama”
输出: true
示例 2:
输入: “race a car”
输出: false

我的想法:

  1. 将字符串中除小写字母,大写字母,数字之外的字符全部去掉,得到一个新的字符串;
  2. 将新的字符串翻转,与翻转前相比较(忽略大小写),若相同返回true;否则返回false;
  3. 或者可以不反转字符串,利用双指针:一个指向头,一个指向尾,比较对应位置上的字符是否相同(忽略大小写),若有不同,返回false;否则指针向中间移动;

对应程序:

// java
class Solution {
	// 解法1,对应我的想法2
    public boolean isPalindrome(String s) {
        StringBuilder res = new StringBuilder();
    	for(char c :s.toCharArray()) {
    		if(c < 48 || (c > 57 && c < 65) || (c > 90 && c < 97) || c > 122) {
    			continue;
    		}
    		
    		res.append(c);
    	}
        
    	return res.toString().equalsIgnoreCase(res.reverse().toString());
    }
	// 解法2:对应我的想法3
	public boolean isPalindrome1(String s) {
		StringBuilder temp = new StringBuilder();
		for(char c : s.toCharArray()) {
			if(c < 48 || (c > 57 && c < 65) || (c > 90 && c < 97) || c > 122) {
    			continue;
    		}
			
			temp.append(Character.toLowerCase(c));
		}
		
		int start = 0;
		int end = temp.length() - 1;
		
		while(start < end) {
			if(temp.charAt(start) != temp.charAt(end)) {
				return false;
			}
			
			start++;
			end--;
		}
		
		return true;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值