tx_orderByFrequency_11~20

89. 格雷编码

难度中等141 收藏 分享 切换为英文 关注 反馈

格雷编码是一个二进制数字系统,在该系统中,两个连续的数值仅有一个位数的差异。

给定一个代表编码总位数的非负整数* n*,打印其格雷编码序列。格雷编码序列必须以 0 开头。

输入:1
输出:[0,1]
0
1
输入: 2
输出: [0,1,3,2]
解释:
00 - 0
01 - 1
11 - 3
10 - 2

对于给定的 n,其格雷编码序列并不唯一。

思路 由 1->2;
0
1
在最左边+0变成
00
01
和原来不变,将最左边从0变成1.
10
11,此时01与10是连续的数值但是其有两个位数不同。因此,在将第一位从0变成1,则并对称的向上取右边的数,则能满足格雷性质!
即,用2^(k-1) 倒序加上之前的格雷序列。

class Solution {
    public List<Integer> grayCode(int n) {
        List<Integer> temp = new ArrayList();
        temp.add(0);
        temp.add(1);
        for(int i=2;i<=n;i++){
            int t = 1<<(i-1);
            int j = temp.size()-1;
            for(int k = j;k>=0;k--){
                temp.add(temp.get(k)+t);
            }
        }
        return temp;
    }
}

940. 不同的子序列 II

给定一个字符串 S,计算 S 的不同非空子序列的个数。

因为结果可能很大,所以返回答案模**** 10^9 + 7.

输入:"abc"
输出:7
解释:7 个不同的子序列分别是 "a", "b", "c", "ab", "ac", "bc", 以及 "abc"。

思路:动态规划;
动态规划要点:

  1. 把空字符串加入子序列,最后再减去。dp[0] = 1;
  2. 如果新增的第k个字符a是已经出现过的,假设在第i次出现过,那么第i次新增时,会把a加在i-1的结果集当中,而第k个字符a又会新增在结果集当中,造成重复。需要把这一部分减去。
    动态规划状态转移方程如下:
    加入的第个k字符a如果在之前没有出现过,dp[k+1] = 2×dp[k];
    如果出现过, dp[k+1] = 2×dp[k]- dp[i-1];其中i为a上一次出现位置的dp索引。
class Solution {
    public int distinctSubseqII(String S) {
        long MOD = (long) (1e9+7);
        long[] dp = new long[S.length()+1];
        int n = S.length();
        dp[0] = 1;
        HashMap<Character,Integer> map = new HashMap();
        for(int i=0;i<S.length();i++){
            if(!map.containsKey(S.charAt(i))){
                dp[i+1] = dp[i]*2;
            }else{
                dp[i+1] = dp[i]*2 - dp[map.get(S.charAt(i))-1];
            }
            dp[i+1] %= MOD;
            map.put(S.charAt(i),i+1);
        }
        if(dp[n]<0) dp[n]+=MOD;
        return (int) ((dp[S.length()]-1));
    }
}

546. 移除盒子

给出一些不同颜色的盒子,盒子的颜色由数字表示,即不同的数字表示不同的颜色。
你将经过若干轮操作去去掉盒子,直到所有的盒子都去掉为止。每一轮你可以移除具有相同颜色的连续 k 个盒子(k >= 1),这样一轮之后你将得到 k*k 个积分。
当你将所有盒子都去掉之后,求你能获得的最大积分和

输入:

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

23
解释:

[1, 3, 2, 2, 2, 3, 4, 3, 1]
----> [1, 3, 3, 4, 3, 1] (33=9 分)
----> [1, 3, 3, 3, 1] (1
1=1 分)
----> [1, 1] (33=9 分)
----> [] (2
2=4 分)

思路:本题较难,需要用三维dp来记录结果。
dp[l][r][k],其中dp[l][r]是从l起到r终,k指的是与boxes[r]相同的有多少个解。

  dfs(boxes,0,boxes.length-1,0)

动态转移方程如下:
两种情况: 1、将最后的k个r直接消去。dp[l][r][k] = dp[l][r-1][0] + (k+1)^2
2、 如果前面的颜色有和第r个相同的,考虑按照该index将其分割,并将r移动到index后面。那么会有:这种方式的意思就是先将第index到第r之间的递归消除,这样多了一个连续的颜色,再消除。
dfs(boxes,0,index,k+1) + dfs(boxes,i+1,r-1,0);
由于index可能有多个,遍历取max

代码如下:

class Solution {

    int[][][] dp = new int[101][101][101]; //题目告知boxes长度最大为100;
    public int removeBoxes(int[] boxes) {
        int res = dfs(boxes,0,boxes.length-1,0);
        return res;
    }

    public int dfs(int[] boxes, int l, int r, int k){
        if(l>r){
            return 0;
        }
        if(dp[l][r][k]!=0){
            return dp[l][r][k];
        }
        while(r>1&&boxes[r]==boxes[r-1]){
            r = r-1;
            k = k+1;
        }
        int max = 0;
        max = Math.max(max,dfs(boxes,l,r-1,0)+(k+1)*(k+1));
        
        for(int i=l;i<r;i++){
            if(boxes[i]==boxes[r]){
                max = Math.max(max,dfs(boxes,l,i,k+1)+dfs(boxes,i+1,r-1,0));
            }
        }
        dp[l][r][k] = max;
        return max;
    }
}

394. 字符串解码

给定一个经过编码的字符串,返回它解码后的字符串。

编码规则为: k[encoded_string],表示其中方括号内部的 encoded_string 正好重复 k 次。注意 k 保证为正整数。

你可以认为输入字符串总是有效的;输入字符串中没有额外的空格,且输入的方括号总是符合格式要求的。

此外,你可以认为原始数据不包含数字,所有的数字只表示重复的次数 k ,例如不会出现像 3a2[4] 的输入。

s = "3[a]2[bc]", 返回 "aaabcbc".
s = "3[a2[c]]", 返回 "accaccacc".
s = "2[abc]3[cd]ef", 返回 "abcabccdcdcdef".

思路: 本题很自然能想到栈;类似于操作数入栈;
以实例"3[a2[c]]"为例,首先将 3 [ a 2 [ c 入栈,碰到 ] 时,将出栈直到碰到 [ 后,将数字出栈。生成一个字符串 "cc", 这里需要注意先入先出,如2[bc],出栈后变成cbcb。需要反转。反转后重新入栈。
然后继续 碰到 ],继续将栈内元素出栈,直到碰到[,则有。3cca,同样注意反转后入栈。
最后得到栈为{accaccacc}。此时出栈后将顺序颠倒即可。

class Solution {
    public String decodeString(String s) {
        Stack<Character> stack = new Stack();
        String result = "";
        for(int i=0;i<s.length();i++){
            if(s.charAt(i)!=']'){
                stack.push(s.charAt(i));
            }
            else{
                String temp = "";
                while(stack.peek()!='['){
                    temp = String.valueOf(stack.pop()) + temp;
                }
                stack.pop();
                String nums = "";
                while(!stack.isEmpty()&&stack.peek()>='0'&&stack.peek()<='9'){
                    nums = String.valueOf(stack.pop()) + nums;
                }
                int num = Integer.parseInt(nums);
                String res =  "";
                for(int j=0;j<num;j++){
                    res += temp;
                }
                result = res;
                char[] support = res.toCharArray();
                for(char ch:support){
                    stack.push(ch);
                }
            }
        }
        String aaa="";
        while(!stack.isEmpty()) {
            aaa=stack.pop()+aaa;
        }
        return aaa;
        }
}

379. 电话目录管理系统

设计一个电话目录管理系统,让它支持以下功能:

get: 分配给用户一个未被使用的电话号码,获取失败请返回 -1
check: 检查指定的电话号码是否被使用
release: 释放掉一个电话号码,使其能够重新被分配

// 初始化电话目录,包括 3 个电话号码:0,1 和 2。
PhoneDirectory directory = new PhoneDirectory(3);

// 可以返回任意未分配的号码,这里我们假设它返回 0。
directory.get();

// 假设,函数返回 1。
directory.get();

// 号码 2 未分配,所以返回为 true。
directory.check(2);

// 返回 2,分配后,只剩一个号码未被分配。
directory.get();

// 此时,号码 2 已经被分配,所以返回 false。
directory.check(2);

// 释放号码 2,将该号码变回未分配状态。
directory.release(2);

// 号码 2 现在是未分配状态,所以返回 true。
directory.check(2);

思路: 用一个boolean数组表示,每当get时,找到数组中为true的值,更新为false;若找不到,返回-1;代码不难,在于找到合适的数据结构来表示。如果用hashMap,则需要维护index,并且release时索引需要改变,增大了难度。

class PhoneDirectory {

    boolean[] sys;
    int size = 0;

    /** Initialize your data structure here
        @param maxNumbers - The maximum numbers that can be stored in the phone directory. */
    public PhoneDirectory(int maxNumbers) {
        this.sys = sys;
        this.size = maxNumbers;
        sys = new boolean[size];
        Arrays.fill(sys,true);
    }
    
    /** Provide a number which is not assigned to anyone.
        @return - Return an available number. Return -1 if none is available. */
    public int get() {
        for(int i=0;i<size;i++){
            if(sys[i]){
                sys[i] = false;
                return i;
            }
        }
        return -1;
    }
    
    /** Check if a number is available or not. */
    public boolean check(int number) {
        return sys[number];
    }
    
    /** Recycle or release a number. */
    public void release(int number) {
        sys[number] = true;
    }
}

/**
 * Your PhoneDirectory object will be instantiated and called as such:
 * PhoneDirectory obj = new PhoneDirectory(maxNumbers);
 * int param_1 = obj.get();
 * boolean param_2 = obj.check(number);
 * obj.release(number);
 */

835. 图像重叠

给出两个图像 ABAB 为大小相同的二维正方形矩阵。(并且为二进制矩阵,只包含0和1)。

我们转换其中一个图像,向左,右,上,或下滑动任何数量的单位,并把它放在另一个图像的上面。之后,该转换的重叠是指两个图像都具有 1 的位置的数目。

(请注意,转换不包括向任何方向旋转。)

最大可能的重叠是什么?
输入:A = [[1,1,0],
[0,1,0],
[0,1,0]]
B = [[0,0,0],
[0,1,1],
[0,0,1]]
输出:3
解释: 将 A 向右移动一个单位,然后向下移动一个单位。

思路: 注意该题是求移动,不存在循环的情况。因此可以用一个temp数组表示移动后的矩阵。
移动后与另一个数组比较重叠区域。注意,A、B都可以移动。求更重叠更大的那个。

class Solution {
    public int largestOverlap(int[][] A, int[][] B) {
        int m = A.length;
        int n = A[0].length;
        int max = 0;
        for(int right = 0;right<n;right++){
            for(int down = 0;down<m;down++){
                int count = 0;
                int[][] temp = new int[2*m][2*n]; 
                for(int i=0;i<m;i++){
                    for(int j=0;j<n;j++){
                        int x = i+down;
                        int y = j+right;
                        temp[x][y] = A[i][j];
                        if(B[i][j]==1&&temp[i][j]==B[i][j]){
                            count ++;
                        }
                    }
                }
                max = Math.max(max,count);
                count = 0;
                temp = new int[2*m][2*n]; 
                for(int i=0;i<m;i++){
                    for(int j=0;j<n;j++){
                        int x = i+down;
                        int y = j+right;
                        temp[x][y] = B[i][j];
                        if(A[i][j]==1&&temp[i][j]==A[i][j]){
                            count ++;
                        }
                    }
                }
                max = Math.max(max,count);
            }
        }
        return max;
    }

}

186. 翻转字符串里的单词 II

给定一个字符串,逐个翻转字符串中的每个单词。
输入: ["t","h","e"," ","s","k","y"," ","i","s"," ","b","l","u","e"]
输出: ["b","l","u","e"," ","i","s"," ","s","k","y"," ","t","h","e"]

思路: 原地翻转;

class Solution {
    public void reverseWords(char[] s) {
        int left = 0;
        int right = s.length-1;
        reverse(s,left,right);
        for(int i=0;i<right;i++){
            if(s[i]==' '){
                reverse(s,left,i-1);
                left = i+1;
            }
        }
        reverse(s,left,right);
    }
    public void reverse(char[] s ,int left ,int right){
        while(left<right){
            char temp = s[left];
            s[left] = s[right];
            s[right] = temp;
            left++;
            right--;
        }
    }
}

271. 字符串的编码与解码

请你设计一个算法,可以将一个 字符串列表 编码成为一个 字符串。这个编码后的字符串是可以通过网络进行高效传送的,并且可以在接收端被解码回原来的字符串列表。

思路:编码 加字符串列表加起来,中间用非ASCII 码分割;
解码时,不用split函数,以防止分割码直接被去除。减少了[""]的情况。

public class Codec {

    // Encodes a list of strings to a single string.
    public String encode(List<String> strs) {

        StringBuilder sb  = new StringBuilder();
        for(String str:strs){
            sb.append(str);
            sb.append(Character.toString((char)257));
        }
        return sb.toString();
    }

    // Decodes a single string to a list of strings.
    public List<String> decode(String s) {
        List<String> res = new ArrayList<>();
        if (s == null || s.length() == 0) return res;
        List<Character> t = new ArrayList();
        System.out.println(s);
        for(int i=0;i<s.length();i++){
            if(s.charAt(i)!=Character.toString((char)257).charAt(0)){
                t.add(s.charAt(i));
            }else{
                if(t.size()!=0){
                    char[] a = new char[t.size()];
                    for(int j=0;j<t.size();j++){
                        a[j] = t.get(j);
                    }
                    res.add(String.valueOf(a));
                }else{
                    res.add("");
                }
                t= new ArrayList();
            }
        }

        return res;
    }
}

// Your Codec object will be instantiated and called as such:
// Codec codec = new Codec();
// codec.decode(codec.encode(strs));

672. 灯泡开关 Ⅱ

现有一个房间,墙上挂有 n 只已经打开的灯泡和 4 个按钮。在进行了 m 次未知操作后,你需要返回这 n 只灯泡可能有多少种不同的状态。

假设这 n 只灯泡被编号为 [1, 2, 3 ..., n],这 4 个按钮的功能如下:

将所有灯泡的状态反转(即开变为关,关变为开)
将编号为偶数的灯泡的状态反转
将编号为奇数的灯泡的状态反转
将编号为 3k+1 的灯泡的状态反转(k = 0, 1, 2, ...)

输入: n = 1, m = 1.
输出: 2
说明: 状态为: [开], [关]

输入: n = 2, m = 1.
输出: 3
说明: 状态为: [开, 关], [关, 开], [关, 关]

输入: n = 3, m = 1.
输出: 4
说明: 状态为: [关, 开, 关], [开, 关, 开], [关, 关, 关], [关, 开, 开].

思路:如果只有前奇数翻转和偶数翻转,奇数一定和灯泡1相同,偶数一定和灯泡2相同; 如果有3k+1翻转出现,由于两次翻转抵消。假设一次。 那么 1、4、7中的奇数一定与1相同。 判断1与3是否相等,如果不等,那么3k+1翻转出现了。 那么3k+1中的偶数,一定是与2相反,其余偶数一定与2相同。 3k+1中的奇数,一定与3相同,其余奇数,一定与1相同。
因此,只需要前三个灯泡的状态,就可以确定所有灯泡的状态。
假设四种翻转分别为A、B、C、D;
若翻转次数=1;return 1;
翻转次数为1,从A、B、C、D选一个,因此在n>=3时,结果为4;
若m=2;则翻转只能取到 “” 、A、B、C、AD、BD、CD七种, 因此,在n>=3时,结果为7;
若m>=3;翻转最多取到所有情况, “” 、A、B、C、D、AD、BD、CD八种,因此,在n>=3时,结果为8;
n等于1时,最多两种;
n等于2时,最多4种。

class Solution {
   public int flipLights(int n, int m) {
       if(n == 0 || m == 0){
           return 1;
       }
       if(m == 1){
           return n<3 ? n+m:4;
       }
       else if (m == 2 ){
           return n<3 ? n*m:7;
       }
       else{
           return n<3 ? 2*n:8;
       }
   }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,110评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,443评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,474评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,881评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,902评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,698评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,418评论 3 419
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,332评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,796评论 1 316
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,968评论 3 337
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,110评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,792评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,455评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,003评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,130评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,348评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,047评论 2 355

推荐阅读更多精彩内容

  • 第5章 引用类型(返回首页) 本章内容 使用对象 创建并操作数组 理解基本的JavaScript类型 使用基本类型...
    大学一百阅读 3,237评论 0 4
  • 题目格雷编码是一个二进制数字系统,在该系统中,两个连续的数值仅有一个位数的差异。 给定一个代表编码总位数的非负整数...
    HITZGD阅读 704评论 0 1
  • 题目: 格雷编码是一个二进制数字系统,在该系统中,两个连续的数值仅有一个位数的差异。 给定一个代表编码总位数的非负...
    answerLDA阅读 374评论 0 1
  • 最近在看一本禁书,真的是禁书。比较有意思的是先出版了,后面就全面下架,电子书渠道也没有了。这本书是武志红写的《巨婴...
    闻舒阅读 291评论 0 1
  • 定过很多目标,写过很多计划,但是总是在调整变化中,不是因为不合理,而是因为没实践。 上过一些网课,好的有,索然无味...
    叙是诗珠宝阅读 239评论 0 0